find コマンドの -exec オプション内でファイル名とパスを分離する

find コマンドの -exec オプション内でファイル名とパスを分離する

findエスケープと式の評価に苦労しています。 ...構造内でコマンドを実行しようとしています。この-exec COMMAND構造では、COMMAND1 つのファイルに対して操作が行われ、stdout に出力されます。これをCOMMANDコマンド ラインで通常どおり使用するには、次のように新しいファイルにリダイレクトするだけです。

COMMAND inputfilename.md > outputfilename.md.conf

これはうまく動作します。しかし、再帰的にループしたい場合は全てディレクトリとそのサブディレクトリ内のファイルを でリダイレクトする場合find -exec、ファイル名とパスを分離して適切にリダイレクトする方法がわかりません。たとえば、次のコードではエラーが発生します。

find ./ *.md -not -path './/.git/*' -exec COMMAND '{} > ~/wiki/newdirectory/{}.cong' \;

はファイルパス全体を拡張します。と{}のさまざまな組み合わせを試しましたが、評価できないようです(代わりに、文字列「basename」などが表示されます)。たとえば、これは機能しませんでした。テキスト「basename」はbasenamedirname

find ./ *.md -not -path './/.git/*' -exec COMMAND  '{} > ~/wiki/newdirectory/''basename {}''.conf' \;

(このエラーが返されます: 'No such file or directory - .//newdirectory/README.md.conf > ~/wiki/newdirectory/basename .//newdirectory/README.md.conf')。

ご協力いただければ幸いです。要約すると、目的は次のとおりです。

  1. *.mdディレクトリ内の一致するすべてのファイルを再帰的に反復処理する
  2. 各反復で同じ文字列であるCOMMAND inputfile.md > ~/newdirectory/inputfile.md.confところを実行します。inputfile

ありがとう!

答え1

何をするにしても、シェルを呼び出して、結果に応じて場所が決まるファイルにコマンド出力をリダイレクトする必要がありますfind

find ./ *.md -not -path './/.git/*' -exec sh -c 'COMMAND "$0" > ~/wiki/newdirectory/"${0##*/}.cong"' {} \;

{}シェル スクリプト内では置換しないでください。これはすべてのシステムでサポートされているわけではありません。サポートされている場合でも、ファイル名をシェル構文の一部として扱うため、通常は機能しません。たとえば、 というファイルが;rm -rf ~;.mdあると、すべてのファイルが消去されます。

${0##*/}純粋な文字列操作を使用して、ファイルのベース名を取得します。 を使用することもできます$(basename -- "$0")

答え2

find承認されれば-execdir、これは機能するはずです

find . -name '*.md' -not -path './/.git/*' -execdir COMMAND {} > ~/wiki/newdirectory/{}.cong \;

交互に

find . -name '*.md' -not -path './/.git/*' -exec bash -c \
'for f; do COMMAND "$f" > ~/wiki/newdirectory/"${f##*/}".cong; done' _ {} +

関連情報