find execでforループを使用する

find execでforループを使用する
 -> find  .. -name bin  -exec  for file in {}/* ; do echo $file ; done  \;

   -bash: syntax error near unexpected token `do'

このコマンドの正しい構文は何ですか?

答え1

for複数のステートメント(-loopなど)を引数として使用するには、明示的にシェルを呼び出す-exec必要がありますbash。例:

find .. -name bin -exec bash -c 'for file in "$1"/* ; do echo "$file" ; done' none {}  \;

スペースやその他の敵対的な文字を含むファイル名にも安全です。

bash -c動作原理

bashは、次の形式のコマンドを使用して呼び出すことができます。

bash -c some_complex_commands arg0 arg1 arg2 ...

この場合、bashは文字列内のすべてを実行しますsome_complex_commands。このコマンドは通常のシェルを使用して使用できます位置パラメータarg0上記のコマンドの後の最初の引数はに割り当てられ$0、2番目の引数はに割り当てられ$1、3番目の引数はに割り当てられる$2式です。

通常のシェルスクリプトを実行すると、$0これはスクリプト名と$1コマンドラインに表示される最初の引数です。この伝統を維持しながらスクリプトに適切な名前がないため、ファイル名(find表記)を割り当てるようにbash -cコマンドが作成されました。 {}$1none$0

答え2

欲しいものと反対の結果を得ているようです。この試み:

for f in `find .. -name bin`
do
echo $f
done

答え3

次のように基本要素を使用して疑似コードの出力を近似できますfind

find .. -path \*/bin/\* ! -name .\* 

...で始まらない名前だけを印刷する必要があります。その名前はある程度上位ディレクトリに根を置いており、より大きな範囲はというディレクトリに根を置いています/bin

通常、サブプロセスでループを実行するさまざまな実際の目的を考えることができますが、渡された引数に対してfind -execシェルドグロブを実行することは可能ではないと思いますfind。擬似コードと同じことを行うにはprintf- これを使用すると、引数を文字通り出力に変換できるため、次のようにできます。

find .. -type d -name bin -exec sh -c '
    printf %s\\n "$0/"*' {} \;

...ループせずに印刷とワイルドカードを実行しますfor。ただし、このコマンドとサンプルコマンドの1つの違いは、名前と一致する結果の仕様と型がない場合、-type d結果はdにbinなることです。したがって、標準出力に記録されているecho内容の多くを見る可能性が高い。bin/*。もちろん、があっても解決-type dされるという保証はありません*。空のディレクトリ.またはファイルのみを含むディレクトリは一致するものをレンダリングしないため、これを見ることができます。

{} \;また、この例では他の方法よりはるかに遅くなる可能性がある基本的な形式を使用しているため、擬似コードであることに注意してください。printfたとえば、次のように操作を再試行します。

find .. -type d -name bin -exec sh -c '
    for d do printf %s\\n "$d/"*; done' -- {} +

...これはまだ空のglobの状況のリスクがありますが、-exec一度に1つのシェルを一致させるのではなく、実行時に他のプロセスに合理的に渡すことができるだけの引数を収集し、引数を位置パラメータ配列に渡します。 - ループsh"$@"使用できますfor d do printf...

これで、単に結果を印刷する以外の別の操作を実行したい場合(文内で繰り返すときに一般的に役に立つと思います)、前の例-execに戻って次のようなものを組み合わせることができます。-path-exec

find .. -path \*/bin/\* -exec sh -c '
    for arg do : something with "$arg"
done' -- {} +

関連情報