find -exec コマンドの使用 {} + コマンドの呼び出し回数

find -exec コマンドの使用 {} + コマンドの呼び出し回数

マンページの状態を探す:

   -exec command {} +
          This variant of the -exec action runs the specified command on the selected files,
          but the command line is built by appending each selected file name at the end;
          the total number of invocations of the  command  will  be
          much  less than the number of matched files.

findいつもこれが一度だけ実行されると思いましたcommand。コマンドが何回呼び出されたかを知る方法はありますか?

私の考えでは、これが一度だけ発生した場合は、処理commandするには大きすぎるパラメータのリストを作成する危険があるため、これは重要です。ただし、 find が呼び出しを分割すると (たとえばparallel)、この状況は次のようになります。緩和される。

答え1

使用されるバッファはfindバージョンによって異なります。ここに提供したSuSEボックスのサイズは約256Kbのようです。

したがって、「コマンド」が呼び出された回数を計算するには、見つかった各ファイルパスの長さを知る必要があります。これは、(ほぼ)すべてのパス長の合計に区切りスペースに1を加え、コマンド自体を引いたものになります。バッファ領域サイズで割った値です。

たとえば、平均パス長が200バイトの20,000個のファイルを見つけました。これは、4,020,000バイトを256Kbで割った値が15.33であるため、約16回の呼び出しが必要です。

2回の連続呼び出しの間にファイルパスを破壊する必要がないことを考慮すると、正確な計算は少し複雑ですが、おおよその数値を得ることができます。

バラよりここ1スレッド(ソースコードを含む)の場合、サイズは32Kbと報告されており、不必要に低いと見なされます。find はいシステム制限を使用してください。私は実験していません)coreutilsバージョンは次のように推論されます。128KBのものより4倍多いようです。

答え2

制限は、find(1)バッファとコマンドが処理する内容(カーネルによって異なります)によって異なります。最後の割合がパフォーマンスにとって非常に重要ではない場合、システムのデフォルト設定は問題ありません。

パフォーマンスが心配な場合は検討してくださいみんなこれを行うシステムと測定するボトルネックはどこにありますか?あなたはそうする可能性があります非常にあなたが見つけたものに驚いてください。 Bentleyは、優れたWriting Efficient Programs(Prentice-Hall、1982)(悲しいことに絶版)で本質的に使用されておらず、致命的なバグのあるプログラムをもたらした注意深い「最適化」に関するいくつかの話を共有しています。コードは「高速」プログラムのアイドル状態を最適化します。リング。オペレーティングシステムを測定した結果、コンピュータの時間の大部分を占めることがわかりました。人々は悪名高い非効率性がどこにあるかを推測するのはうまくいきません。さらに、より高いレベル(システムアーキテクチャ、組織全体、アルゴリズム、およびデータ構造)の作業は、詳細な作業よりも価値があります。

答え3

予備の説明:マニュアルと質問はcommandコマンドを表すために使用されますが、POSIXは文字通り名前付きユーティリティを定義するためcommand、私の答えはを使用しますcmmnd


cmmnd実際に実行して呼び出し回数だけ数えたい場合(注意してください)後ろに finddone)次に、計算可能な操作(stderrで印刷、ログファイルとして印刷、ビープ音など)を実行するラッパーを作成し、最後にを実行しますcmmnd

#!/bin/sh
echo "invoking cmmnd" >&2
cmmnd "$@"

次に、insideのwrapper代わりにを使用してください。cmmndfind

長すぎないコマンドは生成時にfind使用され、/absolute/path/to/wrapperラッパーはを使用します/absolute/path/to/cmmnd。後者が長い場合、それを含むいくつかのコマンドラインが長すぎる可能性があります。したがって、このアプローチは私たちが望むものほど単純ではありません。findたとえば、文字通り追加のスラッシュを提供して古いパスを拡張できます/absolute/path/to/////wrapper


今私はあなたが番号を知りたいと仮定します今後あなたは走ることにしましたcmmnd。このような場合のように、2回呼び出すのは(何らかの理由で)悪いことであり、一度だけ実行するようにしたいとcmmnd思います。find

cmmnd "$@"上記のコメント付きラッパーを使用することができます。以下はいくつかの異なるアイデアです(最終的にはあまり変わりませんが)。

あなたがこれをしたいとしましょう:

find . -exec cmmnd … {} +

定数パラメータを表します)cmmnd実際の絶対パスが何であるかを調べます。たとえば/bin/cmmnd。次に、次のように実行します。

find . -exec /aaa/zzzzz … {} +

/aaa/zzzzzと同じ長さの名前を持つ存在しないコマンドはどこにありますか/bin/cmmnd?これで、findコマンドラインは/aaa/zzzzzコマンドラインと同じ長さで作成されます/bin/cmmnd。あなたは得るでしょう

find: '/aaa/zzzzz': No such file or directory

1回以上。必要な数字を取得するには、数字を数えます。この簡単な方法は次のとおりです。

find . -exec /aaa/zzzzz … {} + 2>&1 | wc -l

find可能な最高ではありません返品たとえば、permission denied見つかったいくつかのファイルを印刷します。ただし、/aaa/zzzzz1行(空白行も可能)のみを印刷する有効な実行可能ファイルを作成すると、次のように動作します。

find . -exec /aaa/zzzzz … {} + | wc -l

もう1つの改善点は、ツール名を/a(代わりに)指定し、必要な期間に応じてツールなどと呼ぶ/aaa/zzzzzことです。例://///a/////////////////a

find . -exec /////////a … {} + | wc -l

完全性のために、a次のように見えます。

#!/bin/sh
echo

私たちのラッパーはそうではないのとほぼ同じですが、cmmnd "$@"標準出力を使用します。

メモ:

  • 正確な文字数は/重要ではありません。何人かの人の間違いでは結果が変わらない徹底的に。必要なら推定その結果、///////////aそこに至る経路がcmmnd異常に長くない限り、盲目的に左右を使用することができる。正確な使用法に応じて/a下限が提供されます。

  • 実際には他のテストが先行することがよくあります-exec cmmnd … {} +。などcmmndと交換しても、/////////a他のテストは引き続き実行されます。-exec最初にパス名のパスを決定するので、これを無視しないでください。しかし、テストが何かを実行または変更するcmmnd場合は、これらの 。

    -delete -exec cmmnd … {} +たとえば、削除されたファイルのレポートを生成するファイル削除を使用できますcmmnd。この場合、使用すると/////////aファイルが削除されます。いいえレポートを生成します。したがって、行動する前に考えてください。

  • テスト/ジョブ/この-exec /////////a … {} +stdoutに何も印刷しないことを確認してください。または/a別のチャンネルを使用してください。

  • それ以外の場合でも、指定されたディレクトリツリーを処理して(他の)テストを実行するのに時間がかかることがありますcmmnd

答え4

まあ、標準テキストは次のように言います。

複数のパス名のセットのサイズは、ユーティリティの実行によってシステムの{ARG_MAX}制限を超えないように制限する必要があります。

したがって、実行するには大きすぎるパラメータのリストを作成しないでください。これはそのような機能のポイントを無効にします。

実行する呼び出しの数は実装によって異なりますので、大きく気にする必要はありません。標準では、-exec同じ句への呼び出しは重複しないと約束します。これは、外部状態で何かを実行する場合の精度に関連する可能性があります。

ただし、Linuxでは、コマンドラインパラメータの実際の最大サイズはスタックサイズに基づいており、間接参照を使用して変更できますulimit -s。たとえばxargsfind私のDebianおよびUbuntu製品は実際に実行時に制限を確認しないため、理論的に問題が発生する可能性があります。

$ mkdir bar
$ touch bar/{00000..99999}
$ ulimit -Ss 512
$ getconf ARG_MAX
131072
$ find bar -type f -exec sh ./args.sh {} +
find: ‘sh’: Argument list too long
find: ‘sh’: Argument list too long
...

ただし、デフォルトはulimit -s8192 であるため、非常に制限されたシステムを除いて、問題が発生する可能性はありません。

関連情報