-> 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
コマンドが作成されました。 {}
$1
none
$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' -- {} +