1

SO の周りや外部の特定のコマンド (cat など) のプログレス バーに関するいくつかのアイデアを見てきました。しかし、私の質問は標準から少し外れているようです...

現在、find次の例のように、シェルでコマンドの機能を使用しています。

find . -name file -exec cmd "{}" \;

「cmd」は通常、ディスク領域を解放するための圧縮機能または削除ツールです。いつ "。" 非常に大きく、これには数分かかることがあります。「ステータス」を報告する機能が必要です。

完了するまで、ある種の進行状況バー、完了率、または印刷期間 (つまり、作業中....) を表示する方法はありますか? 可能であれば、別のfind. 出来ますか?

前もって感謝します。

4

3 に答える 3

0

ユーティリティ () がインストールされている場合はdialog、見栄えの良いローリング ディスプレイを簡単に作成できます。

find . -type f -name glob -exec echo {} \; -exec cmd {} \; |
dialog --progressbox "Files being processed..." 12 $((COLUMNS*3/2))

への引数--progressboxは、ボックスのタイトルです (オプション、数字のようには見えません)。テキスト行の高さとテキスト列の幅。dialogプレゼンテーションをカスタマイズするためのオプションがたくさんあります。上記は、開始するためのものです。

dialog「ゲージ」とも呼ばれる進行状況バーもありますが、@glennjackman が回答で指摘しているように、進行状況を表示するには、どれだけの作業が必要かを知る必要があります。これを行う 1 つの方法は、find コマンドの出力全体を収集し、その中のファイルの数を数え、蓄積された出力から目的のタスクを実行することです。ただし、これは、作業を開始するために find コマンドが終了するまで待機することを意味し、望ましくない場合があります。

興味深い課題だったという理由だけで、次の解決策を思いつきました。これは、考えられるすべてのシェルの落とし穴を回避しようとするため、過剰に設計されている可能性があります (それでも、おそらく一部が欠けている可能性があります)。これは、次の 2 つのシェル ファイルで構成されます。

# File: run.sh

#!/bin/bash
# Usage: run.sh root-directory find-tests
#
# Fix the following path as required
PROCESS="$HOME/bin/process.sh"
TD=$(mktemp --tmpdir -d gauge.XXXXXXXX)
find "$@" -print0 |
tee >(awk -vRS='\0' 'END{print NR > "'"$TD/_total"'"}';
      ln -s "$TD/_total" "$TD/total") |
{ xargs -0 -n50 "$PROCESS" "$TD"; printf "XXX\n100\nDone\nXXX\n"; } |
dialog --gauge "Starting..." 7 70 
rm -fR "$TD"

# File: process.sh

#!/bin/bash
TD="$1"; shift
TOTAL= 
if [[ -f $TD/count ]]; then COUNT=$(cat "$TD/count"); else COUNT=0; fi
for file in "$@"; do
  if [[ -z $TOTAL && -f $TD/total ]]; then TOTAL=$(cat "$TD/total"); fi
  printf "XXX\n%d\nProcessing file\n%q\nXXX\n" \
         $((COUNT*100/${TOTAL:-100})) "$file"
  #
  # do whatever you want to do with $file
  #
  ((++COUNT))
done
echo $COUNT > "$TD/count"

いくつかのメモ:

上記にはたくさんの gnu 拡張機能が散らばっています。完全なリストは作成していませんが、確かに%qprintf 形式が含まれています (これは%s. ファイル名リストを NUL で終了するために使用される--tmpdirフラグと、 mktemp.

run.shを使用teeして、見つかったファイルの数を ( で) 同時にカウントし、awkファイルの処理を開始します。

-n50引数を指定すると、xargsfind が最初のファイルを見つけられずに多くの時間を費やした場合に起動が遅れるのを避けるために、最初の 50 個のファイルだけを待機するようになります。必要ないかもしれません。

への-vRS='\0'引数は、行区切り文字として aawkを使用し、アクションを(およびオプションを) に一致させます。これはすべて、ファイルパスに改行を含めることができる場合にのみ必要です。NUL-print0find-0xargs

awkにカウントを書き込み、完全に書き込まれる前に読み取られる非常にありそうもない競合状態を回避するために、_totalにシンボリック リンク_totalします。シンボリックリンクはアトミックであるため、この方法で行うと、存在しないか、完全に記述されていることが保証されます。totaltotaltotal

特に処理作業がファイル サイズに関連している場合 (たとえば、圧縮など) は、ファイルを単にカウントするのではなく、ファイルの合計サイズをカウントした方がよい場合があります。それはかなり単純な変更です。また、並列実行機能を使用したくなるかもしれませんがxargs、並列プロセス間で処理されたファイルの合計を調整する作業がもう少し必要になります。

を持っていない管理された環境を使用している場合dialog、最も簡単な解決策はsshdialog. run.sh から削除し、代わりに呼び出しに| dialog --gauge "Starting..." 7 70入れます。sshssh user@host /path/to/run.sh root-dir find-tests | dialog --gauge "Starting..." 7 70

于 2013-06-29T06:51:34.393 に答える
0

The trick with find is that you add two -print clauses, one at the start, and one at the end. You then use awk (or perl) to update and print a line counter for each unique line. In this example I tell awk to print to stderr.

Any duplicate lines must be the result of the conditions we specified, so we treat that special. In this example, we just print that line:

find . -print -name aa\* -print |
awk '$0 == last {
    print "" > "/dev/fd/2"
    print
    next
}
{
    printf "\r%d", n++ > "/dev/fd/2"
    last=$0
}'

It's best to leave find to just report pathnames, and do further processing from awk, or just add another pipeline. (Because the counters are printed to stderr, those will not interfere.)

于 2013-06-30T18:58:46.277 に答える