xargs 構造を動作させることができません

xargs 構造を動作させることができません

私は奇妙な問題を抱えているxargs
を持っていますxargsコマンドをエコーすると完璧に動作するにもかかわらず、動作しない構造があります。私のワンライナーは次のとおりです。

 exiftool -p exifprintformat  -if '$Subject =~/DATA/i' -q  *.pdf |grep pdf |sed 's/ //g'|xargs|xargs -0 -I % pdftk % cat output binder1.pdf  

そして出力

エラー: ファイルが見つかりません。 エラー: PDF ファイルを開けませんでした: 20170105170516234.pdf 20170105173126944.pdf 20170105173209758.pdf 20170621163418079.pdf

  • exiftool件名タグにDATAという単語を含むすべてのPDFを選択します 。
  • ファイル名のみを印刷するように -p exifprintformat指示します。exiftool
  • greppdfの行のみを選択します 。
  • 空白を削除しますsed
  • 最初のものはxargすべての行を1つの文字列にし、2番目のものはbindコマンドを構築します。

exiftool -p exifprintformat -if '$Subject =~/DATA/i' -q *.pdf |grep pdf |sed 's/ //g'|xargs|xargs -I{} echo pdftk {} cat output bidner1.pdf

私は

pdftk 20170105170516234.pdf 20170105173126944.pdf 20170105173209758.pdf 20170621163418079.pdf cat 出力バインダー1.pdf

それは完璧に機能します。

明らかに、私は何か間違ったことをしています...しかし、何ですか?

答え1

いくつかの間違いと不必要な複雑さがあります:-

  1. 二重xargs呼び出しは、2 番目に 1 行の入力が参照されるため、{}一致するファイル名すべてを含む単一の文字列に 1 回だけ置換されますが、echo出力にはこの違いは表示されません (echo a bと比較してくださいecho "a b")。
  2. 引数は、入力引数の間にnull ( ) 文字が必要であるが、そのような文字がないことを-0意味します。これにより、入力が単一のパラメータとして扱われることも強制されます。xargs'\0'
  3. 条件が一致したときにファイル名のみを出力すると、1 行に 1 つのファイル名が取得され、または をxargs必要とせずに に直接パイプできます。grepsed
  4. 残念ながら、xargs -I入力行ごとに 1 つのコマンドが強制され、末尾のパラメータを追加するオプションはありませんが、末尾のパラメータを入力ストリームに追加するという簡単な回避策があります。

これは、末尾のパラメータが追加された簡略化されたコマンドです (-if一致する PDF がない別の条件でテストしました)。

{ exiftool -p '${FileName}' -if '$Subject =~/DATA/i' -q *.pdf; \
  echo -e "cat\noutput\nbinder1.pdf"; } | xargs -d'\n' pdftk

このxargs -d'\n'オプションにより、ファイル名に空白が埋め込まれている場合でもコマンドが機能します。

答え2

xargs のマニュアルページには次のように書かれています:

-I 置換文字列

  Replace occurrences of replace-str in the initial-arguments with
  names read from standard input.   Also, unquoted blanks do not
  terminate input items; instead the separator is the newline
  character.  Implies -x and -L 1.

言い換えれば、" 20170105170516234.pdf 20170105173126944.pdf 20170105173209758.pdf 20170621163418079.pdf"という単一の引数が残ることになります。

xargs を完全に廃止し、コマンドを次のように並べ替えることをお勧めします。

pdftk $(exiftool -p exifprintformat -if '$Subject =~/DATA/i' -q *.pdf |grep pdf |sed 's/ //g'| tr '\n' ' ') cat output binder1.pdf

これはすべて、ファイル名にスペースが含まれていないことを前提としています (いずれにしても sed を使用してすべてのスペースを削除しているため、安全な前提です)。

関連情報