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
)。