find -exec と xargs を介したパイプの動作が異なる

find -exec と xargs を介したパイプの動作が異なる

chmod go+w隠しファイルを含む特定のフォルダで再帰的に実行したかったので、まず試してみました

find . -name ".*" -o -name "*" -exec chmod go+w {} \;

しかし、隠しファイルには影響がないことが分かりました。確認するために、

find . -name ".*" -o -name "*"

隠しファイルがリストされました。また、その部分を除外すると隠しファイルがchmodされることに気づきました-o -name "*"(もちろん隠しファイル以外も除外されます)。最後の試みは、代わりにxargsを使用することでした。

find . -name ".*" -o -name "*" | xargs chmod go+w

最終的に期待どおりに動作しました。最初のスニペットで何が間違っているのでしょうか?

Red Hat Enterprise Linux Server リリース 6.8 (サンティアゴ)

GNU bash、バージョン 4.3.42(1)-リリース (x86_64-unknown-linux-gnu)

答え1

解決策は、2 つの名前テストを括弧で結合することです。

これを説明するために、3 つの通常のファイルを含むディレクトリを考えてみましょう。

$ ls -a
.  ..  .hidden1  .hidden2  not_hidden

さて、元のコマンドを見てみましょう:

$ find . -name ".*" -o -name "*" -exec echo Found {} \;
Found ./not_hidden

隠しファイルでないファイルのみが見つかります。

次に、括弧を追加して 2 つの名前テストをグループ化します。

$ find . \( -name ".*" -o -name "*" \) -exec echo Found {} \;
Found .
Found ./not_hidden
Found ./.hidden1
Found ./.hidden2

すべてのファイルが見つかりました。

解決策は括弧を使用することです。

詳細情報

-name "*"元のコマンドでは、と の間に演算子はありません-exec ... \;。したがって、findはデフォルトの演算子である論理積を想定します。論理積は論理和 ( -o) よりも結合が強いため、コマンドは次のように解釈されます。

find . \( -name ".*" \) -o \( -name "*" -exec echo Found {} \; \)

これは、exec最初のname条件が一致しなかった場合にのみ実行されることを意味します。

詳細については、オペレーターのセクションman find

なしで何が起こるか-exec

簡単なものを使ってみましょう-print:

$ find . -name ".*" -o -name "*" -print
./not_hidden

ご覧のとおり、上記のように暗黙の論理積で-printバインドされています。-name "*"

しかし、アクションを指定しない場合に何が起こるか考えてみましょう。

$ find . -name ".*" -o -name "*"
.
./not_hidden
./.hidden1
./.hidden2

ここで、すべてのファイルが見つかりました。その理由は、このバージョンでは-oのみオペレーター。

関連情報