ファイルが存在することを確認したら、ファイル名のリストをxargsに渡す方法は?

ファイルが存在することを確認したら、ファイル名のリストをxargsに渡す方法は?

command1以下のようにファイル名のリストを返すコマンド()があります。

/consumer/a.txt
/consumer/b.txt
/consumer/doesnotexist.txt

出力をパイプするときにcommand1 | xargs command2 command2ファイルのいずれかが存在しないと、例外が発生します。

存在しないファイルをパイピングする前にどのように削除できますかcommand2?次のことを楽しみにしています

command1 | xargs remove_nonexistant_files | xargs command2

command2受けなければならない

/consumer/a.txt
/consumer/b.txt

入力として。

答え1

command1 |
xargs sh -c 'for p do [ -f "$p" ] && printf "%s\n" "$p"; done' sh |
xargs command 2

途中の追​​加ビットは、デフォルトで指定されたxargsコマンドライン引数を繰り返し、既存の一般ファイル(または一般ファイルへのシンボリックリンク)に対応するパス名を印刷する短いスクリプトへの別の呼び出しです。これにより、これらの既存のパス名がパイプラインの最後の部分に渡されます。

これは、すべてのパス名に新しい行、スペース、タブが含まれていないと想定します。

答え2

command1リストが目的の形式で出力されると仮定すると、xargs以下を定義できます。

existing_plain_readable_files_only() {
  perl -le "for (@ARGV) {
    if (-f && -r) {s/'/'\\\\''/g; print qq('\$_')}
  }" -- "$@"
}

次のように使用してください。

command1 | xargs existing_plain_readable_files_only | xargs command2

perlここでは '-f演算子 を使用します。定期的な-rファイルのみ(ディレクトリ、デバイス、パイプは除く)読めるユーザーが(command2読みたいと仮定して)私たちはエスケープされた一重引用符文字自体を除いて一重引用符を使用します\

xargsこれはすべてのシェルでサポートされている参照です。つまり、この関数を使用して、任意のファイルのリストを含むシェル配列を処理することもできます。

eval "array2=($(existing_plain_readable_files_only "${array1[@]}"))"

(これはksh93、、、zshまたはbashシェルmkshを仮定しますyash)。

関連情報