簡単に言うと:
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
find
find
純粋なコマンドを使用する代わりに、ループやGNUとwhile read
組み合わせることができますparallel
。見つかったすべてのパスに対して新しいシェルを起動する必要はないので、両方ともおそらく両方のものよりも高速ですfind
。-exec
find
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"
から読み取られた正しく参照された項目{}
に置き換えられます。引用しないでください。parallel
stdin
{}
parallel
スクリプトを起動したのと同じシェルを使用してスクリプトを実行します。スクリプトで関数をparallel
使い始めたら。bash
bash
「読みながら読み」を使ったソリューション
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
。