find
を-execdir
で実行すると、期待した結果が得られません。
例えば:
mkdir -p a/b/c
find . -type d -execdir touch foo \;
$ tree a
a
├── b
│ ├── c
│ └── foo
└── foo
ディレクトリc
にはfoo
ファイルが含まれていません。 find
にアクセスして各ディレクトリでローカルに何かをするにはどうすればよいですか?
一致するすべてのファイル(つまり、すべてのディレクトリ)について、find
はそれを含むディレクトリ(つまり、その親ディレクトリ)に切り替え、指定されたコマンドを実行します。コマンドは一致の名前を使用しないので、すべてのディレクトリに作用することは決してありません。この特定のディレクトリツリーについては、
(cd . && touch foo) # because ./a matches
(cd ./a && touch foo) # because ./a/b matches
(cd ./a/b && touch foo) # because ./a/b/c matches
すべてのディレクトリにファイルを作成するには、_find
の実装が引数内で-exec
を許可している限り、-execdir
の代わりに{}
を使用できます(ほとんどの場合、特に私はすべてのものです):
find . -type d -exec touch {}/foo +
POSIXの移植性のために、ディレクトリ名とファイルベース名を手動でアセンブルする必要があります。
find . -type d -exec sh -c 'touch "$0/foo"' {} \;
または(少し速い)
find . -type d -exec sh -c 'for d; do touch "$d/foo"; done' _ {} +
または、bashの再帰的なワイルドカードマッチングを使用できます。 (kshやzshの対応する機能とは異なり、find
コマンドとは異なり)bashはディレクトリへのシンボリックリンクの下で再帰することに注意してください。
shopt -s globstar
for d in **/*/; do touch -- "$d/foo"; done
Zshソリューション:
touch ./**/(e\''REPLY+=foo'\')
コマンドは、一致したファイルを含むすべてのディレクトリで実行されます。 c
にはディレクトリが含まれていないため、一致せず、そこで実行されません。
解決策は、次のようにディレクトリ名をexecdir引数に追加することです。
find . -type d -execdir touch {}/foo \;
man file
-execdir command {} +
Like -exec, but the specified command is run from the subdirectory containing the matched file
一致するディレクトリc
はb
ディレクトリにあるため、execが実行されます。ディレクトリではなくファイルを探している場合は、期待どおりに機能します。
ディレクトリの完全なリストが提供されるため、ディレクトリをxargs
に送信することで、希望どおりの結果を得ることができます。