検索プロセス中にファイル名を変更できますか?

検索プロセス中にファイル名を変更できますか?

find{}「このファイル」(ish)を表すために使用されます。次のようににさまざまなファイルを入力できますmyprog

find ./tests/ -name *.in -exec myprog -i {} \;

中に名前を変更する方法はありませんか{}?私の場合は、-i入力ファイルと出力を定義し、-o出力でファイル名を少し変更して「a.in」が「a.out」を生成したいと思いました。理想的には、次のことを達成したいと思います。

find ./tests/ -name *.in -exec myprog -i {} -o {}.out \;

また、出力ディレクトリのパスが異なる場合があります。この場合、出力は到着しない可能性がありますが/tests/到着する可能性があります/tests_20220615/

例を含む複数のページを見てみましたが、find同様のものが表示されないので、「いいえ」ではありませんか?

Bashまたはzshでループを使用してこれを実行する方法があることはわかっていますが、可能なトラップのリストは素晴らしい( "nullglob"?!)、これを行うことができれば、findこの愚かな奴にとってより安全に見えます。

ベストアンサー1

findファイルパスを変更できず、一部の実装findでは他のコンテンツと関連付けることができず、{}一部はマルチパスもサポートしていませんが、{}変換を実行できるシェルなどの一部のコマンドは常に実行できます。

find ./tests/ -name '*.in' -type f -exec sh -c '
  ret=0
  for file do
    myprog -i "$file" -o "${file%.*}.out" || ret="$?"
  done
  exit "$ret"' sh {} +

myprog上記では、直接実行するのではなく、検出されたファイルへのパスshとともにいくつかのインラインコードを実行して渡します(できるだけ多くのファイルを渡すのではなく){} +{} ';'

shこれらのファイルを順番に繰り返し、拡張子の削除myprogなどの変換を適用して呼び出します。${file%.*}

周囲の引用符を参照してください*.in。これがなければ、コマンドを実行するシェルはパターンをそのまま渡すfindのではなく、名前で終わる現在のディレクトリのファイルのリストに展開しようとします。.infind

sh上記で呼び出しが失敗した場合、失敗した終了myprog状態で終了すると言いました。失敗はの終了ステータスに反映されるため、必要に応じてアクションを実行するfindか、errexitこのオプションが有効な場合はスクリプトを終了できます。ただし、最初の失敗時に中断することは不可能ですmyprog

シェルを使用している場合は、zsh内部で見つけることもできます。

set -o errexit
for file (./tests/**/*.in(ND.)) myprog -i $file -o $file:r.out

最初の失敗時に終了し、語彙順でリストを処理します(oNこの順序を無効にするには、いつでもglob修飾子を追加できます)。

find別のアプローチは、ファイルを印刷して変換を実行するいくつかのコマンドにパイプしてからパイプすることですxargs

find ./tests/ -name '*.in' -type f -print0 |
  gawk -v RS='\0' -v ORS='\0' -v OFS='\0' '
    {
      filein = fileout = $0; sub(/\.in$/, ".out", fileout)
      print "-i", filein, "-o", fileout
    }' | xargs -r0 -n4 myprog

呼び出しが失敗すると、xargsゼロ以外の終了状態が再び返されます。myprogGNUはそのオプションを使用して複数の呼び出しを並列に実行xargsできます。-P

あるいは、perl後処理して実行させることもできます。

find ./tests/ -name '*.in' -type f -print0 |
  perl -l -0ne '
    system("myprog", "-i", $_, "-o", s/\.in\Z/.out/r) == 0 or
      $ret = 1;
    END {exit $ret}'

シェルをfind設定しない限り、(サポートされている場合)メソッドの後処理された出力は、失敗した終了状態(存在する場合)(たとえば、特定のディレクトリに入ることができない場合)をマスクします。pipefail

パイプを使用すると、myprog標準入力にも影響します(たとえば、ユーザーにメッセージを表示する必要がある場合など)。 GNUは標準入力を開き、他のxargsメソッドはそのまま残ります。これは / のパイプになることを意味します。/dev/nullperlfindgawk

おすすめ記事