-execの検索とカウンタ/進行の増加

-execの検索とカウンタ/進行の増加

簡単に言うと:

Q:カウンターfind -execループを維持するにはどうすればよいですか?


マイユースケース:

あちこちに散らばっているディレクトリをたくさん移動しなければならないのでこうしました。

find . -type d -name "prefix_*" \
    -exec sh -c '
        new_path="/new/path/$(basedir "$1")";
        [ -d "$new_path" ] || mv "$1" "$new_path";
    ' find_sh {} \;

(実際のコマンドは、それを構成する要素に関するいくつかのメタデータを読んだので、より複雑です。とにかく、/new/pathコマンド自体について議論したくありません。これは質問の一部ではなくユースケースにすぎません。)

うまく動作しますが、時間がかなり時間がかかるので、進捗状況を追跡したいと思います。

だから、ファイルに書き込むカウンタを追加しました。

i=$(cat ~/find_increment || echo 0);
echo $((i+1)) | tee ~/find_increment;

これもうまく機能しますが、次のような気がします。本物約100,000個のディスクの読み取りと書き込みを実行するのは悪い考えです。

ディスクの代わりに書き込みを検討しましたが、ramdiskこれを実行するために必要な環境にはそのオプションはありません。

実行の間にカウンターを維持するより良い方法はありますか-exec

答え1

findfind純粋なコマンドを使用する代わりに、ループやGNUとwhile read組み合わせることができますparallel。見つかったすべてのパスに対して新しいシェルを起動する必要はないので、両方ともおそらく両方のものよりも高速ですfind-execfind

GNU Parallelを使用したソリューション

GNUと比較すると、次parallelの利点がありますwhile read

  • 正しい結果を得る方が簡単です。いいえIFS=、また-r必須です。
  • 組み込みジョブ番号変数{#}
    より便利な文字列の置換を確認するには、次の点を確認してください。地図時間
  • 必要に応じて簡単に並列化できます。
    削除されると、デフォルトで-j1はコア数だけワーカースレッドがあります。
script='
    echo Processing job number {#}
    new_path="/new/path/$(basedir {})"
    [ -d "$new_path" ] || mv {} "$new_path"
'
find … -print0 | parallel -0 -j1 "$script"

から読み取られた正しく参照された項目{}に置き換えられます。引用しないでください。parallelstdin{}

parallelスクリプトを起動したのと同じシェルを使用してスクリプトを実行します。スクリプトで関数をparallel使い始めたら。bashbash

「読みながら読み」を使ったソリューション

find … -print0 |
while IFS= read -r -d '' old_path; do
    echo Processing job number "$((++job))"
    new_path="/new/path/$(basedir "$old_path")"
    [ -d "$new_path" ] || mv "$old_path" "$new_path"
done 

答え2

可能であれば、そこにカウンタを保存して/dev/shm/ディスクの書き込みを防ぎます。

=>/dev/shm/find_increment代わりに使用してください~/find_increment

関連情報