* NIXでbashまたはその他のシェルでスクリプトを作成するときに、数秒以上かかるコマンドを実行しながら進行状況バーが必要です。
たとえば、大きなファイルをコピーしたり、大きなtarファイルを開いたりします。
シェルスクリプトにプログレスバーを追加するにはどのような方法をお勧めしますか?
行を上書きすることでこれを実装できます。端末に\r
を書き込まずに行の先頭に戻るには、\n
を使用します。
行を進め終わったら\n
を書きます。
echo -ne
を使用して、
\n
を表示しない\r
のようなエスケープシーケンスを認識するため。これがデモです。
echo -ne '##### (33%)\r'
sleep 1
echo -ne '############# (66%)\r'
sleep 1
echo -ne '####################### (100%)\r'
echo -ne '\n'
以下のコメントでは、長い行で始めて短い行を書きたい場合、pukはこれを「失敗」としています。
スピナーの使い方 にも興味があるかもしれません :
もちろんです。
i=1 sp="/-\|" echo -n ' ' while true do printf "\b${sp:i++%${#sp}:1}" done
ループが繰り返されるたびに、sp文字列内の次の文字が表示され、最後に達すると折り返されます。 (iは表示する現在の文字の位置、$ {#sp}はsp文字列の長さです).
\ b文字列は 'バックスペース'文字に置き換えられます。別の方法として、\ rを使って行の先頭に戻ることもできます。
速度を落としたい場合は、(printfの後の)ループの内側にsleepコマンドを入れてください。
POSIXで同等なものは次のようになります。
sp='/-\|' printf ' ' while true; do printf '\b%.1s' "$sp" sp=${sp#?}${sp%???} done
多くの作業を行うループがすでにある場合は、各反復の始めに次の関数を呼び出してスピナーを更新できます。
sp="/-\|" sc=0 spin() { printf "\b${sp:sc++:1}" ((sc==${#sp})) && sc=0 } endspin() { printf "\r%s\n" "$@" } until work_done; do spin some_work ... done endspin
いくつかの投稿は、コマンドの進行状況を表示する方法を示しました。それを計算するためには、あなたがどれだけ進歩したかを見る必要があります。 BSDシステムでは、dd(1)のようないくつかのコマンドはSIGINFO
シグナルを受け取り、それらの進行状況を報告します。 Linuxシステムでは、いくつかのコマンドはSIGUSR1
と同様に応答します。この機能が利用できる場合は、入力をdd
を通してパイプ処理して、処理されたバイト数を監視できます。
あるいは、 lsof
を使用してファイルの読み取りポインタのオフセットを取得し、それによって進行状況を計算することもできます。 pmonitor という名前のコマンドを作成しました。これは、指定したプロセスまたはファイルの処理の進行状況を表示します。それを使えば、次のようなことができます。
$ pmonitor -c gzip
/home/dds/data/mysql-2015-04-01.sql.gz 58.06%
以前のバージョンのLinuxおよびFreeBSDシェルスクリプトは 私のブログ にあります。
linuxのコマンドpvを使用します。
サイズがストリームの途中であるかどうかはわかりませんが、速度と合計が得られるので、そこからどれくらいの時間をかけてフィードバックを得るかを判断できるため、ハングアップしていないことがわかります。
私が先日書いた簡単なプログレスバー機能を手に入れました:
#!/bin/bash
# 1. Create ProgressBar function
# 1.1 Input is currentState($1) and totalState($2)
function ProgressBar {
# Process data
let _progress=(${1}*100/${2}*100)/100
let _done=(${_progress}*4)/10
let _left=40-$_done
# Build progressbar string lengths
_fill=$(printf "%${_done}s")
_empty=$(printf "%${_left}s")
# 1.2 Build progressbar strings and print the ProgressBar line
# 1.2.1 Output example:
# 1.2.1.1 Progress : [########################################] 100%
printf "\rProgress : [${_fill// /\#}${_empty// /-}] ${_progress}%%"
}
# Variables
_start=1
# This accounts as the "totalState" variable for the ProgressBar function
_end=100
# Proof of concept
for number in $(seq ${_start} ${_end})
do
sleep 0.1
ProgressBar ${number} ${_end}
done
printf '\nFinished!\n'
またはからそれを引っ掛ける、
https://github.com/fearside/ProgressBar/
私は選択された答えよりセクシーな何かを探していたので、私自身のスクリプトもそうしました。
私はそれを置く github progress-bar.sh
progress-bar() {
local duration=${1}
already_done() { for ((done=0; done<$elapsed; done++)); do printf "▇"; done }
remaining() { for ((remain=$elapsed; remain<$duration; remain++)); do printf " "; done }
percentage() { printf "| %s%%" $(( (($elapsed)*100)/($duration)*100/100 )); }
clean_line() { printf "\r"; }
for (( elapsed=1; elapsed<=$duration; elapsed++ )); do
already_done; remaining; percentage
sleep 1
clean_line
done
clean_line
}
progress-bar 100
GNU tar にはシンプルなプログレスバーの機能を提供する便利なオプションがあります。
(...)他の利用可能なチェックポイントアクションは 'ドット'(または '。')です。これは、標準のリストストリーム上に単一のドットを印刷するようにtarに指示します。
$ tar -c --checkpoint=1000 --checkpoint-action=dot /var
...
次のようにしても同じ効果が得られます。
$ tar -c --checkpoint=.1000 /var
Pipeview(pv)ユーティリティを使って私のシステムで動作するもっと簡単な方法。
srcdir=$1
outfile=$2
tar -Ocf - $srcdir | pv -i 1 -w 50 -berps `du -bs $srcdir | awk '{print $1}'` | 7za a -si $outfile
これにより、コマンドがまだ実行中であることを視覚化できます。
while :;do echo -n .;sleep 1;done &
trap "kill $!" EXIT #Die with parent if we die prematurely
tar zxf packages.tar.gz; # or any other command here
kill $! && trap " " EXIT #Kill the loop and unset the trap or else the pid might get reassigned and we might end up killing a completely different process
これは、バックグラウンドで実行され "。"をエコーする無限whileループを作成します。一秒ごと。これにより、シェルに.
が表示されます。 tar
コマンドまたは必要なコマンドを実行します。そのコマンドの実行が終了すると、バックグラウンドで最後に実行されたジョブがkill - これは無限whileループです.
似たようなものは見たことがありません...私の非常に単純な解決策:
#!/bin/bash
BAR='####################' # this is full bar, mine is 20 chars
for i in {1..20}; do
echo -ne "\r${BAR:0:$i}" # print $i chars of $BAR from 0 position
sleep .1
done
echo -n
- 末尾に改行なしで印刷するecho -e
- 印刷中に特殊文字を解釈します"\r"
- キャリッジリターン、行の先頭に戻るための特殊文字私はタイピングコードをシミュレートするために単純な「ハッキングビデオ」の中でずっと前にそれを使いました。 ;)
ほとんどのunixコマンドはあなたがこれを行うことができるから直接のフィードバックのようなものをあなたに与えることはありません。いくつかはあなたが使うことができる標準出力または標準エラー出力をあなたに与えるでしょう。
Tarのようなものでは、-vスイッチを使用して、出力を1行ごとに小さなアニメーションを更新するプログラムに渡すことができます。 tarがファイルのリストを書き出すので、プログラムはアニメーションを更新できます。達成率を達成するには、ファイル数を知り、行数を数える必要があります。
私の知る限り、cpはこの種の出力を与えません。 cpの進行状況を監視するには、ソースファイルと宛先ファイルを監視し、宛先のサイズを監視する必要があります。ファイルサイズを取得するために stat(2) システムコールを使って小さなCプログラムを書くことができます。これは、ソースのサイズを読み取り、次に宛先ファイルをポーリングし、それまでに書き込まれたファイルのサイズに基づいて%completeバーを更新します。
まず第一に、バーだけがパイプ進行メーターではありません。もう1つの(おそらくもっとよく知られている)pv(パイプビューア)です。
次に、barとpvをこのように使うことができます。
$ bar file1 | wc -l
$ pv file1 | wc -l
あるいは:
$ tail -n 100 file1 | bar | wc -l
$ tail -n 100 file1 | pv | wc -l
あなたが引数で与えられたファイルを扱っているコマンドでbarとpvを利用したいなら、1つの役に立つトリック、例えばファイル1、ファイル2をコピーし、 プロセス置換 を使用します。
$ copy <(bar file1) file2
$ copy <(pv file1) file2
プロセス置換は一時的なfifoパイプファイル/ dev/fd /を作成し、このパイプを通して(カッコの中で)実行されたプロセスから標準出力に接続し、コピーすることで普通のファイルと同じように見えます転送します。
更新:
barコマンド自体はコピーも可能です。男バーの後:
bar --in-file /dev/rmt/1cbn --out-file \
tape-restore.tar --size 2.4g --buffer-size 64k
しかし、プロセス置換は私の考えではそれを行うためのより一般的な方法です。それはcpプログラム自体を使います。
私の解決策は、現在圧縮解除されて書かれているtarballの割合を表示します。 2GBのルートファイルシステムイメージを書き出すときにこれを使います。あなたは本当にこれらのことのためにプログレスバーが必要です。 tarballの圧縮されていない合計サイズを取得するにはgzip --list
を使用します。それから、ファイルを100の部分に分割するのに必要なブロッキングファクタを計算します。最後に、ブロックごとにチェックポイントメッセージを表示します。 2GBのファイルの場合、これは約10MBのブロックを与えます。それが大きすぎる場合は、BLOCKING_FACTORを10または100で割ることができますが、割合の点で見栄えの良い出力を印刷するのは困難です。
Bashを使用していると仮定すると、次のシェル関数を使用できます。
untar_progress ()
{
TARBALL=$1
BLOCKING_FACTOR=$(gzip --list ${TARBALL} |
Perl -MPOSIX -ane '$.==2 && print ceil $F[1]/50688')
tar --blocking-factor=${BLOCKING_FACTOR} --checkpoint=1 \
--checkpoint-action='ttyout=Wrote %u% \r' -zxf ${TARBALL}
}
編集:更新されたバージョンについては私 githubページ をチェックしてください
私はこの質問に対する回答に満足していませんでした。私が個人的に探していたのは、APTで見られるような派手なプログレスバーでした。
私はAPTのCのソースコードを見て、私自身のbashと同等のものを書くことにしました。
このプログレスバーは端末の下部にうまく表示され、端末に送信される出力を妨げることはありません。
バーは現在100文字幅に固定されていることに注意してください。あなたがそれを端末のサイズに合わせることを望むなら、これも同様に達成するのがかなり簡単です(私のgithubページの最新版はこれをうまく処理します)。
ここに自分のスクリプトを掲載します。使用例
source ./progress_bar.sh
echo "This is some output"
setup_scroll_area
sleep 1
echo "This is some output 2"
draw_progress_bar 10
sleep 1
echo "This is some output 3"
draw_progress_bar 50
sleep 1
echo "This is some output 4"
draw_progress_bar 90
sleep 1
echo "This is some output 5"
destroy_scroll_area
スクリプト(私の代わりにgithubにあるバージョンを強くお勧めします):
#!/bin/bash
# This code was inspired by the open source C code of the APT progress bar
# http://Bazaar.launchpad.net/~ubuntu-branches/ubuntu/trusty/apt/trusty/view/head:/apt-pkg/install-progress.cc#L233
#
# Usage:
# Source this script
# setup_scroll_area
# draw_progress_bar 10
# draw_progress_bar 90
# destroy_scroll_area
#
CODE_SAVE_CURSOR="\033[s"
CODE_RESTORE_CURSOR="\033[u"
CODE_CURSOR_IN_SCROLL_AREA="\033[1A"
COLOR_FG="\e[30m"
COLOR_BG="\e[42m"
RESTORE_FG="\e[39m"
RESTORE_BG="\e[49m"
function setup_scroll_area() {
lines=$(tput lines)
let lines=$lines-1
# Scroll down a bit to avoid visual glitch when the screen area shrinks by one row
echo -en "\n"
# Save cursor
echo -en "$CODE_SAVE_CURSOR"
# Set scroll region (this will place the cursor in the top left)
echo -en "\033[0;${lines}r"
# Restore cursor but ensure its inside the scrolling area
echo -en "$CODE_RESTORE_CURSOR"
echo -en "$CODE_CURSOR_IN_SCROLL_AREA"
# Start empty progress bar
draw_progress_bar 0
}
function destroy_scroll_area() {
lines=$(tput lines)
# Save cursor
echo -en "$CODE_SAVE_CURSOR"
# Set scroll region (this will place the cursor in the top left)
echo -en "\033[0;${lines}r"
# Restore cursor but ensure its inside the scrolling area
echo -en "$CODE_RESTORE_CURSOR"
echo -en "$CODE_CURSOR_IN_SCROLL_AREA"
# We are done so clear the scroll bar
clear_progress_bar
# Scroll down a bit to avoid visual glitch when the screen area grows by one row
echo -en "\n\n"
}
function draw_progress_bar() {
percentage=$1
lines=$(tput lines)
let lines=$lines
# Save cursor
echo -en "$CODE_SAVE_CURSOR"
# Move cursor position to last row
echo -en "\033[${lines};0f"
# Clear progress bar
tput el
# Draw progress bar
print_bar_text $percentage
# Restore cursor position
echo -en "$CODE_RESTORE_CURSOR"
}
function clear_progress_bar() {
lines=$(tput lines)
let lines=$lines
# Save cursor
echo -en "$CODE_SAVE_CURSOR"
# Move cursor position to last row
echo -en "\033[${lines};0f"
# clear progress bar
tput el
# Restore cursor position
echo -en "$CODE_RESTORE_CURSOR"
}
function print_bar_text() {
local percentage=$1
# Prepare progress bar
let remainder=100-$percentage
progress_bar=$(echo -ne "["; echo -en "${COLOR_FG}${COLOR_BG}"; printf_new "#" $percentage; echo -en "${RESTORE_FG}${RESTORE_BG}"; printf_new "." $remainder; echo -ne "]");
# Print progress bar
if [ $1 -gt 99 ]
then
echo -ne "${progress_bar}"
else
echo -ne "${progress_bar}"
fi
}
printf_new() {
str=$1
num=$2
v=$(printf "%-${num}s" "$str")
echo -ne "${v// /$str}"
}
ファイルをアップロードする
[##################################################] 100% (137921 / 137921 bytes)
仕事が完了するのを待っています
[######################### ] 50% (15 / 30 seconds)
あなたはそれをあなたのスクリプトにコピー&ペーストすることができます。他に何もする必要はありません。
PROGRESS_BAR_WIDTH=50 # progress bar length in characters
draw_progress_bar() {
# Arguments: current value, max value, unit of measurement (optional)
local __value=$1
local __max=$2
local __unit=${3:-""} # if unit is not supplied, do not display it
# Calculate percentage
if (( $__max < 1 )); then __max=1; fi # anti zero division protection
local __percentage=$(( 100 - ($__max*100 - $__value*100) / $__max ))
# Rescale the bar according to the progress bar width
local __num_bar=$(( $__percentage * $PROGRESS_BAR_WIDTH / 100 ))
# Draw progress bar
printf "["
for b in $(seq 1 $__num_bar); do printf "#"; done
for s in $(seq 1 $(( $PROGRESS_BAR_WIDTH - $__num_bar ))); do printf " "; done
printf "] $__percentage%% ($__value / $__max $__unit)\r"
}
ここでは、ファイルをアップロードし、各反復でプログレスバーを再描画します。最大値と現在値の2つの値を取得できれば、実際にどのジョブが実行されるかは関係ありません。
以下の例では、最大値はfile_size
で、現在の値は何らかの関数によって提供され、uploaded_bytes
と呼ばれます。
# Uploading a file
file_size=137921
while true; do
# Get current value of uploaded bytes
uploaded_bytes=$(some_function_that_reports_progress)
# Draw a progress bar
draw_progress_bar $uploaded_bytes $file_size "bytes"
# Check if we reached 100%
if [ $uploaded_bytes == $file_size ]; then break; fi
sleep 1 # Wait before redrawing
done
# Go to the newline at the end of upload
printf "\n"
私はダイアログと - ゲージパラメータを使うのが好きです。 .debパッケージのインストールやその他多くのディストリビューションの基本設定でよく使われます。だから、あなたは車輪を再発明する必要はありません...もう一度
1から100の@stdinまでのint値を入れるだけです。 1つの基本的で愚かな例:
for a in {1..100}; do sleep .1s; echo $a| dialog --gauge "waiting" 7 30; done
私は料理の目的で(chmod u + x permsを含む)この/ bin/Waitファイルを持っています:P
#!/bin/bash
INIT=`/bin/date +%s`
NOW=$INIT
FUTURE=`/bin/date -d "$1" +%s`
[ $FUTURE -a $FUTURE -eq $FUTURE ] || exit
DIFF=`echo "$FUTURE - $INIT"|bc -l`
while [ $INIT -le $FUTURE -a $NOW -lt $FUTURE ]; do
NOW=`/bin/date +%s`
STEP=`echo "$NOW - $INIT"|bc -l`
SLEFT=`echo "$FUTURE - $NOW"|bc -l`
MLEFT=`echo "scale=2;$SLEFT/60"|bc -l`
TEXT="$SLEFT seconds left ($MLEFT minutes)";
TITLE="Waiting $1: $2"
sleep 1s
PTG=`echo "scale=0;$STEP * 100 / $DIFF"|bc -l`
echo $PTG| dialog --title "$TITLE" --gauge "$TEXT" 7 72
done
if [ "$2" == "" ]; then msg="Espera terminada: $1";audio="Listo";
else msg=$2;audio=$2;fi
/usr/bin/notify-send --icon=stock_appointment-reminder-excl "$msg"
espeak -v spanish "$audio"
だから私は置くことができます:
Wait "34 min" "warm up the oven"
または
Wait "dec 31" "happy new year"
私にとってはこれまでのところ最も使いやすくて見栄えがよいのは、pv
またはbar
というコマンドです
例:dd
を使用してドライブ全体のバックアップを作成する必要がある
通常はdd if="$input_drive_path" of="$output_file_path"
を使います
pv
を使えば、このようにすることができます:
dd if="$input_drive_path" | pv | dd of="$output_file_path"
そして、進行は次のように直接STDOUT
に行きます。
7.46GB 0:33:40 [3.78MB/s] [ <=> ]
それが終わった後に要約が上がる
15654912+0 records in
15654912+0 records out
8015314944 bytes (8.0 GB) copied, 2020.49 s, 4.0 MB/s
'\r' + $some_sort_of_progress_msg
をプリントアウトするためのあなた自身のコマンドを書くことについて多くの答えが説明しています。時々問題は、毎秒何百ものこれらの更新を印刷することはプロセスを遅くするということです。
しかし、あなたのプロセスのどれかが出力を生成するなら(例えば7z a -r newZipFile myFolder
はそれを圧縮するときにそれぞれのファイル名を出力します)、それからもっと簡単で速く、痛みがなくそしてカスタマイズ可能な解決策が存在します。
Pythonモジュールtqdm
をインストールしてください。
$ Sudo pip install tqdm
$ # now have fun
$ 7z a -r -bd newZipFile myFolder | tqdm >> /dev/null
$ # if we know the expected total, we can have a bar!
$ 7z a -r -bd newZipFile myFolder | grep -o Compressing | tqdm --total $(find myFolder -type f | wc -l) >> /dev/null
ヘルプ:tqdm -h
。より多くのオプションを使用した例
$ find / -name '*.py' -exec cat \{} \; | tqdm --unit loc --unit_scale True | wc -l
おまけとして、tqdm
を使ってイテラブルをPythonコードでラップすることもできます。
上記の提案を使用して、私は自分のプログレスバーを実装することにしました。
#!/usr/bin/env bash
main() {
for (( i = 0; i <= 100; i=$i + 1)); do
progress_bar "$i"
sleep 0.1;
done
progress_bar "done"
exit 0
}
progress_bar() {
if [ "$1" == "done" ]; then
spinner="X"
percent_done="100"
progress_message="Done!"
new_line="\n"
else
spinner='/-\|'
percent_done="${1:-0}"
progress_message="$percent_done %"
fi
percent_none="$(( 100 - $percent_done ))"
[ "$percent_done" -gt 0 ] && local done_bar="$(printf '#%.0s' $(seq -s ' ' 1 $percent_done))"
[ "$percent_none" -gt 0 ] && local none_bar="$(printf '~%.0s' $(seq -s ' ' 1 $percent_none))"
# print the progress bar to the screen
printf "\r Progress: [%s%s] %s %s${new_line}" \
"$done_bar" \
"$none_bar" \
"${spinner:x++%${#spinner}:1}" \
"$progress_message"
}
main "$@"
Edouard Lopezの仕事に基づいて、私はスクリーンのサイズに合ったプログレスバーを作成しました。見てみな。
また、 Git Hub にも投稿されています。
#!/bin/bash
#
# Progress bar by Adriano Pinaffo
# Available at https://github.com/adriano-pinaffo/progressbar.sh
# Inspired on work by Edouard Lopez (https://github.com/edouard-lopez/progress-bar.sh)
# Version 1.0
# Date April, 28th 2017
function error {
echo "Usage: $0 [SECONDS]"
case $1 in
1) echo "Pass one argument only"
exit 1
;;
2) echo "Parameter must be a number"
exit 2
;;
*) echo "Unknown error"
exit 999
esac
}
[[ $# -ne 1 ]] && error 1
[[ $1 =~ ^[0-9]+$ ]] || error 2
duration=${1}
barsize=$((`tput cols` - 7))
unity=$(($barsize / $duration))
increment=$(($barsize%$duration))
skip=$(($duration/($duration-$increment)))
curr_bar=0
prev_bar=
for (( elapsed=1; elapsed<=$duration; elapsed++ ))
do
# Elapsed
prev_bar=$curr_bar
let curr_bar+=$unity
[[ $increment -eq 0 ]] || {
[[ $skip -eq 1 ]] &&
{ [[ $(($elapsed%($duration/$increment))) -eq 0 ]] && let curr_bar++; } ||
{ [[ $(($elapsed%$skip)) -ne 0 ]] && let curr_bar++; }
}
[[ $elapsed -eq 1 && $increment -eq 1 && $skip -ne 1 ]] && let curr_bar++
[[ $(($barsize-$curr_bar)) -eq 1 ]] && let curr_bar++
[[ $curr_bar -lt $barsize ]] || curr_bar=$barsize
for (( filled=0; filled<=$curr_bar; filled++ )); do
printf "▇"
done
# Remaining
for (( remain=$curr_bar; remain<$barsize; remain++ )); do
printf " "
done
# Percentage
printf "| %s%%" $(( ($elapsed*100)/$duration))
# Return
sleep 1
printf "\r"
done
printf "\n"
exit 0
楽しい
アクティビティの進行状況を表示するには、次のコマンドを試してください。
while true; do sleep 0.25 && echo -ne "\r\\" && sleep 0.25 && echo -ne "\r|" && sleep 0.25 && echo -ne "\r/" && sleep 0.25 && echo -ne "\r-"; done;
または
while true; do sleep 0.25 && echo -ne "\rActivity: \\" && sleep 0.25 && echo -ne "\rActivity: |" && sleep 0.25 && echo -ne "\rActivity: /" && sleep 0.25 && echo -ne "\rActivity: -"; done;
または
while true; do sleep 0.25 && echo -ne "\r" && sleep 0.25 && echo -ne "\r>" && sleep 0.25 && echo -ne "\r>>" && sleep 0.25 && echo -ne "\r>>>"; sleep 0.25 && echo -ne "\r>>>>"; done;
または
while true; do sleep .25 && echo -ne "\r:Active:" && sleep .25 && echo -ne "\r:aCtive:" && sleep .25 && echo -ne "\r:acTive:" && sleep .25 && echo -ne "\r:actIve:" && sleep .25 && echo -ne "\r:actiVe:" && sleep .25 && echo -ne "\r:activE:"; done;
Whileループ内でフラグ/変数を使用して、進捗の値/範囲を確認および表示できます。
私は、 シェルスクリプト で繰り返し文字の文字列を作成するという答えを使用しました。プログレスバーを表示する必要があるスクリプト用の比較的小さいbashバージョンが2つあります(たとえば、多数のファイルを通過するループですが、大きなtarファイルやコピー操作には役立ちません)。 。より速いものは2つの機能から成ります、1つはバー表示のためにストリングを準備することです:
preparebar() {
# $1 - bar length
# $2 - bar char
barlen=$1
barspaces=$(printf "%*s" "$1")
barchars=$(printf "%*s" "$1" | tr ' ' "$2")
}
プログレスバーを表示するためのものです。
progressbar() {
# $1 - number (-1 for clearing the bar)
# $2 - max number
if [ $1 -eq -1 ]; then
printf "\r $barspaces\r"
else
barch=$(($1*barlen/$2))
barsp=$((barlen-barch))
printf "\r[%.${barch}s%.${barsp}s]\r" "$barchars" "$barspaces"
fi
}
それはとして使用することができます:
preparebar 50 "#"
これは、50文字の "#"文字でbarの文字列を準備することを意味します。
progressbar 35 80
35/80の比率に対応する "#"文字の数が表示されます。
[##################### ]
あなた(または他のプログラム)が改行を印刷するまで、functionは同じ行に何度もバーを表示します。最初のパラメータとして-1を入力すると、バーは消えます。
progressbar -1 80
遅いバージョンはすべて1つの機能にあります。
progressbar() {
# $1 - number
# $2 - max number
# $3 - number of '#' characters
if [ $1 -eq -1 ]; then
printf "\r %*s\r" "$3"
else
i=$(($1*$3/$2))
j=$(($3-i))
printf "\r[%*s" "$i" | tr ' ' '#'
printf "%*s]\r" "$j"
fi
}
そしてそれは(上記と同じ例)として使用することができます:
progressbar 35 80 50
Stderrにprogressbarが必要な場合は、各printfコマンドの最後に>&2
を追加するだけです。
これは、gnome zenityを使用している場合にのみ適用可能です。 Zenityはbashスクリプトに素晴らしいネイティブインターフェースを提供します。https://help.gnome.org/users/zenity/stable/
Zenityプログレスバーからの例:
#!/bin/sh
(
echo "10" ; sleep 1
echo "# Updating mail logs" ; sleep 1
echo "20" ; sleep 1
echo "# Resetting cron jobs" ; sleep 1
echo "50" ; sleep 1
echo "This line will just be ignored" ; sleep 1
echo "75" ; sleep 1
echo "# Rebooting system" ; sleep 1
echo "100" ; sleep 1
) |
zenity --progress \
--title="Update System Logs" \
--text="Scanning mail logs..." \
--percentage=0
if [ "$?" = -1 ] ; then
zenity --error \
--text="Update canceled."
fi
私はfearsideによって提供された答えに基づいています
これはOracleデータベースに接続し、RMANリストアの進行状況を取得します。
#!/bin/bash
# 1. Create ProgressBar function
# 1.1 Input is currentState($1) and totalState($2)
function ProgressBar {
# Process data
let _progress=(${1}*100/${2}*100)/100
let _done=(${_progress}*4)/10
let _left=40-$_done
# Build progressbar string lengths
_fill=$(printf "%${_done}s")
_empty=$(printf "%${_left}s")
# 1.2 Build progressbar strings and print the ProgressBar line
# 1.2.1 Output example:
# 1.2.1.1 Progress : [########################################] 100%
printf "\rProgress : [${_fill// /#}${_empty// /-}] ${_progress}%%"
}
function rman_check {
sqlplus -s / as sysdba <<EOF
set heading off
set feedback off
select
round((sofar/totalwork) * 100,0) pct_done
from
v\$session_longops
where
totalwork > sofar
AND
opname NOT LIKE '%aggregate%'
AND
opname like 'RMAN%';
exit
EOF
}
# Variables
_start=1
# This accounts as the "totalState" variable for the ProgressBar function
_end=100
_rman_progress=$(rman_check)
#echo ${_rman_progress}
# Proof of concept
#for number in $(seq ${_start} ${_end})
while [ ${_rman_progress} -lt 100 ]
do
for number in _rman_progress
do
sleep 10
ProgressBar ${number} ${_end}
done
_rman_progress=$(rman_check)
done
printf '\nFinished!\n'
#!/bin/bash
function progress_bar() {
bar=""
total=10
[[ -z $1 ]] && input=0 || input=${1}
x="##"
for i in `seq 1 10`; do
if [ $i -le $input ] ;then
bar=$bar$x
else
bar="$bar "
fi
done
#pct=$((200*$input/$total % 2 + 100*$input/$total))
pct=$(($input*10))
echo -ne "Progress : [ ${bar} ] (${pct}%) \r"
sleep 1
if [ $input -eq 10 ] ;then
echo -ne '\n'
fi
}
これを縮尺で描画する関数を作成することができます。
progress_bar 1
echo "doing something ..."
progress_bar 2
echo "doing something ..."
progress_bar 3
echo "doing something ..."
progress_bar 8
echo "doing something ..."
progress_bar 10
私は組み込みシステム用に純粋なシェルバージョンを作成しました。
/ usr/bin/ddのSIGUSR1シグナル処理機能。
基本的に、 'kill SIGUSR1 $(pid_of_running_dd_process)'を送信した場合、スループット速度と転送量の概要が出力されます。
ddをバックグラウンド化してから定期的に更新を問い合わせ、古い学校のftpクライアントのようなハッシュティックを生成します。
/ dev/stdoutをscpのような非標準的なフレンドリープログラムの宛先として使用する
その結果、あらゆるファイル転送操作を実行して、Xバイトごとにハッシュマークを取得するだけの旧式のFTP 'hash'出力のような進行状況の更新を取得できます。
これは実運用品質のコードではありませんが、あなたはそのアイデアを思いついたのです。かわいいと思います。
それが価値があるもののために、実際のバイト数はハッシュの数に正しく反映されないかもしれません - あなたは丸め問題によって多かれ少なかれ1を持っているかもしれません。テストスクリプトの一部としてこれを使用しないでください、それは単なる目の保養です。そして、はい、私はこれがひどく非効率的であることを知っています - それはシェルスクリプトであり、私はそれについて謝罪をしません。
最後にwget、scp、tftpを付けた例。データを出しているものなら何でも動くはずです。標準出力に対応していないプログラムには/ dev/stdoutを必ず使用してください。
#!/bin/sh
#
# Copyright (C) Nathan Ramella ([email protected]) 2010
# LGPLv2 license
# If you use this, send me an email to say thanks and let me know what your product
# is so I can tell all my friends I'm a big man on the internet!
progress_filter() {
local START=$(date +"%s")
local SIZE=1
local DURATION=1
local BLKSZ=51200
local TMPFILE=/tmp/tmpfile
local PROGRESS=/tmp/tftp.progress
local BYTES_LAST_CYCLE=0
local BYTES_THIS_CYCLE=0
rm -f ${PROGRESS}
dd bs=$BLKSZ of=${TMPFILE} 2>&1 \
| grep --line-buffered -E '[[:digit:]]* bytes' \
| awk '{ print $1 }' >> ${PROGRESS} &
# Loop while the 'dd' exists. It would be 'more better' if we
# actually looked for the specific child ID of the running
# process by identifying which child process it was. If someone
# else is running dd, it will mess things up.
# My PID handling is dumb, it assumes you only have one running dd on
# the system, this should be fixed to just get the PID of the child
# process from the Shell.
while [ $(pidof dd) -gt 1 ]; do
# PROTIP: You can sleep partial seconds (at least on linux)
sleep .5
# Force dd to update us on it's progress (which gets
# redirected to $PROGRESS file.
#
# dumb pid handling again
pkill -USR1 dd
local BYTES_THIS_CYCLE=$(tail -1 $PROGRESS)
local XFER_BLKS=$(((BYTES_THIS_CYCLE-BYTES_LAST_CYCLE)/BLKSZ))
# Don't print anything unless we've got 1 block or more.
# This allows for stdin/stderr interactions to occur
# without printing a hash erroneously.
# Also makes it possible for you to background 'scp',
# but still use the /dev/stdout trick _even_ if scp
# (inevitably) asks for a password.
#
# Fancy!
if [ $XFER_BLKS -gt 0 ]; then
printf "#%0.s" $(seq 0 $XFER_BLKS)
BYTES_LAST_CYCLE=$BYTES_THIS_CYCLE
fi
done
local SIZE=$(stat -c"%s" $TMPFILE)
local NOW=$(date +"%s")
if [ $NOW -eq 0 ]; then
NOW=1
fi
local DURATION=$(($NOW-$START))
local BYTES_PER_SECOND=$(( SIZE / DURATION ))
local KBPS=$((SIZE/DURATION/1024))
local MD5=$(md5sum $TMPFILE | awk '{ print $1 }')
# This function prints out ugly stuff suitable for eval()
# rather than a pretty string. This makes it a bit more
# flexible if you have a custom format (or dare I say, locale?)
printf "\nDURATION=%d\nBYTES=%d\nKBPS=%f\nMD5=%s\n" \
$DURATION \
$SIZE \
$KBPS \
$MD5
}
例:
echo "wget"
wget -q -O /dev/stdout http://www.blah.com/somefile.Zip | progress_filter
echo "tftp"
tftp -l /dev/stdout -g -r something/firmware.bin 192.168.1.1 | progress_filter
echo "scp"
scp [email protected]:~/myfile.tar /dev/stdout | progress_filter
一時的なプログレスバーを表示する必要がある場合は(表示時間を事前に知っておくことで)、次のようにPythonを使用できます。
#!/bin/python
from time import sleep
import sys
if len(sys.argv) != 3:
print "Usage:", sys.argv[0], "<total_time>", "<progressbar_size>"
exit()
TOTTIME=float(sys.argv[1])
BARSIZE=float(sys.argv[2])
PERCRATE=100.0/TOTTIME
BARRATE=BARSIZE/TOTTIME
for i in range(int(TOTTIME)+1):
sys.stdout.write('\r')
s = "[%-"+str(int(BARSIZE))+"s] %d%% "
sys.stdout.write(s % ('='*int(BARRATE*i), int(PERCRATE*i)))
sys.stdout.flush()
SLEEPTIME = 1.0
if i == int(TOTTIME): SLEEPTIME = 0.1
sleep(SLEEPTIME)
print ""
次に、Pythonスクリプトをprogressbar.py
として保存したと仮定すると、次のコマンドを実行してbashスクリプトから進捗バーを表示することができます。
python progressbar.py 10 50
50
文字のプログレスバーと10
秒の間「実行中」が表示されます。
#!/bin/bash
tot=$(wc -c /proc/$$/fd/255 | awk '/ /{print $1}')
now() {
echo $(( 100* ($(awk '/^pos:/{print $2}' < /proc/$$/fdinfo/255)-166) / (tot-166) )) "%"
}
now;
now;
now;
now;
now;
now;
now;
now;
now;
出力:
0 %
12 %
25 %
37 %
50 %
62 %
75 %
87 %
100 %
注:255の代わりに1を入力した場合、標準入力を監視します。2を標準出力にします(ただし、 "tot"を投影出力ファイルサイズに設定するようにソースを変更する必要があります)。