web-dev-qa-db-ja.com

シェルスクリプトにプログレスバーを追加する方法

* NIXでbashまたはその他のシェルでスクリプトを作成するときに、数秒以上かかるコマンドを実行しながら進行状況バーが必要です。

たとえば、大きなファイルをコピーしたり、大きなtarファイルを開いたりします。

シェルスクリプトにプログレスバーを追加するにはどのような方法をお勧めしますか?

363
Tom Feiner

行を上書きすることでこれを実装できます。端末に\rを書き込まずに行の先頭に戻るには、\nを使用します。

行を進め終わったら\nを書きます。

echo -neを使用して、

  1. \nを表示しない
  2. \rのようなエスケープシーケンスを認識するため。

これがデモです。

echo -ne '#####                     (33%)\r'
sleep 1
echo -ne '#############             (66%)\r'
sleep 1
echo -ne '#######################   (100%)\r'
echo -ne '\n'

以下のコメントでは、長い行で始めて短い行を書きたい場合、pukはこれを「失敗」としています。

647
Mitch Haile

スピナーの使い方 にも興味があるかもしれません

Bashでスピナーをすることができますか?

もちろんです。

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
61
Daenyth

いくつかの投稿は、コマンドの進行状況を表示する方法を示しました。それを計算するためには、あなたがどれだけ進歩したかを見る必要があります。 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シェルスクリプトは 私のブログ にあります。

48

linuxのコマンドpvを使用します。

http://linux.die.net/man/1/pv

サイズがストリームの途中であるかどうかはわかりませんが、速度と合計が得られるので、そこからどれくらいの時間をかけてフィードバックを得るかを判断できるため、ハングアップしていないことがわかります。

40
Seth Wegner

私が先日書いた簡単なプログレスバー機能を手に入れました:

#!/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/

36
fearside

私は選択された答えよりセクシーな何かを探していたので、私自身のスクリプトもそうしました。

プレビュー

progress-bar.sh in action

ソース

私はそれを置く 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
23
Édouard Lopez

GNU tar にはシンプルなプログレスバーの機能を提供する便利なオプションがあります。

(...)他の利用可能なチェックポイントアクションは 'ドット'(または '。')です。これは、標準のリストストリーム上に単一のドットを印刷するようにtarに指示します。

$ tar -c --checkpoint=1000 --checkpoint-action=dot /var
...

次のようにしても同じ効果が得られます。

$ tar -c --checkpoint=.1000 /var
17
Wojtek

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
12
leebert

私はまた私の 自身のプログレスバーに貢献したいと思います

半単位ブロック を使用して、サブ文字の精度を達成します。

enter image description here

コードが含まれています

11
nachoparker

これにより、コマンドがまだ実行中であることを視覚化できます。

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ループです.

7
romeror

似たようなものは見たことがありません...私の非常に単純な解決策:

#!/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" - キャリッジリターン、行の先頭に戻るための特殊文字

私はタイピングコードをシミュレートするために単純な「ハッキングビデオ」の中でずっと前にそれを使いました。 ;)

7
cprn

ほとんどの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プログラム自体を使います。

4
thedk

私の解決策は、現在圧縮解除されて書かれている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}
}
4
Noah Spurrier

APTスタイルのプログレスバー(通常の出力を中断しません)

enter image description here

編集:更新されたバージョンについては私 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}"
}
3
polle

これはどのように見えるかです。

ファイルをアップロードする

[##################################################] 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"
3
Vagiz Duseev

私はダイアログ - ゲージパラメータを使うのが好きです。 .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
2
lukassos

'\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コードでラップすることもできます。

https://github.com/tqdm/tqdm/blob/master/README.rst#module

2
casper.dcl

上記の提案を使用して、私は自分のプログレスバーを実装することにしました。

#!/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 "$@"
1
Qub3r

Edouard Lopezの仕事に基づいて、私はスクリーンのサイズに合ったプログレスバーを作成しました。見てみな。

enter image description here

また、 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

楽しい

1
Adriano_epifas

アクティビティの進行状況を表示するには、次のコマンドを試してください。

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ループ内でフラグ/変数を使用して、進捗の値/範囲を確認および表示できます。

1
S471

私は、 シェルスクリプト で繰り返し文字の文字列を作成するという答えを使用しました。プログレスバーを表示する必要があるスクリプト用の比較的小さい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を追加するだけです。

1
Zarko Zivanov

これは、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
1
tPSU

私は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'
0
CH55
#!/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
0
Mike Q

https://github.com/extensionsapp/progre.sh

40パーセントの進捗を作成する:progreSh 40

enter image description here

0
Hello World

私は組み込みシステム用に純粋なシェルバージョンを作成しました。

  • / 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
0

一時的なプログレスバーを表示する必要がある場合は(表示時間を事前に知っておくことで)、次のように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秒の間「実行中」が表示されます。

0
auino
#!/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"を投影出力ファイルサイズに設定するようにソースを変更する必要があります)。

0
Zibri