web-dev-qa-db-ja.com

Linuxでコマンドの途中でxargsですべての引数を渡すにはどうすればよいですか

Linuxではすべてのファイルを1つの引数として渡したいのですが、それはできません。

これは機能しています

ls | sort -n | xargs  -i pdftk  {} cat output combinewd2.pdf

これはコマンドごとに1つの引数を渡しますが、すべてを1つのコマンドに含めたいです。

22
user2027303

これはそれを行う1つの方法です

pdftk $(ls | sort -n) cat output combinewd2.pdf

またはバックティックを使用して

pdftk `ls | sort -n` cat output combinewd2.pdf

コメントで指摘されているように、これはスペースを含むファイル名では機能しません。その場合、evalを使用できます

eval pdftk $(while IFS= read -r file; do
    echo \"$file\"
done < <(ls | sort -n)) cat output combinewd2.pdf

「0 foo」と「1 bar」という名前の2つのファイルがあるとすると、ファイル名が二重引用符で囲まれたevalの結果が目的のコマンドになります。

pdftk " 0 foo " " 1 bar " cat output combinewd2.pdf

ファイル名に改行が含まれている可能性がある場合は、findコマンドを使用します。@ andrewdotnの回答のコメントにある@joeytwiddleの説明を参照してください。次の解決策では、sedコマンドを使用して二重引用符でファイル名を処理し、二重引用符をエスケープします。

eval pdftk $(while IFS= read -r -d '' file; do
    echo \"$file\"
done < <(find . -maxdepth 1 -type f -print0 | \
    sed 's/"/\\"/g'| sort -zn)) cat output combinewd2.pdf
19
amdn

使用する -Iオプション:

echo prefix | xargs -I % echo % post

出力:

prefix post
27
Hongbo Liu

醜いですが、次のように_sh -c_を実行し、xargsから_"${@}"_として渡される引数のリストにアクセスできます。

_ls | sort -n | xargs -d'\n' sh -c 'pdftk "${@}" cat output combinewd2.pdf' "${0}"
_

shのマニュアルページに記載されているように、最後に余分な_"${0}"_があります

-cstring

-cオプションが存在する場合、コマンドはstringから読み取られます。 stringの後に引数がある場合、$ 0で始まる位置パラメーターに割り当てられます。

これをテストするには、まず、他のほとんどのソリューションを台無しにする複雑な名前のファイルをいくつか作成します。

_$ seq 1 100 | xargs -I{} touch '{} with "spaces"'
$ ls
1 with "spaces"    31 with "spaces"  54 with "spaces"  77 with "spaces"
10 with "spaces"   32 with "spaces"  55 with "spaces"  78 with "spaces"
100 with "spaces"  33 with "spaces"  56 with "spaces"  79 with "spaces"
11 with "spaces"   34 with "spaces"  57 with "spaces"  8 with "spaces"
12 with "spaces"   35 with "spaces"  58 with "spaces"  80 with "spaces"
13 with "spaces"   36 with "spaces"  59 with "spaces"  81 with "spaces"
14 with "spaces"   37 with "spaces"  6 with "spaces"   82 with "spaces"
15 with "spaces"   38 with "spaces"  60 with "spaces"  83 with "spaces"
16 with "spaces"   39 with "spaces"  61 with "spaces"  84 with "spaces"
17 with "spaces"   4 with "spaces"   62 with "spaces"  85 with "spaces"
18 with "spaces"   40 with "spaces"  63 with "spaces"  86 with "spaces"
19 with "spaces"   41 with "spaces"  64 with "spaces"  87 with "spaces"
2 with "spaces"    42 with "spaces"  65 with "spaces"  88 with "spaces"
20 with "spaces"   43 with "spaces"  66 with "spaces"  89 with "spaces"
21 with "spaces"   44 with "spaces"  67 with "spaces"  9 with "spaces"
22 with "spaces"   45 with "spaces"  68 with "spaces"  90 with "spaces"
23 with "spaces"   46 with "spaces"  69 with "spaces"  91 with "spaces"
24 with "spaces"   47 with "spaces"  7 with "spaces"   92 with "spaces"
25 with "spaces"   48 with "spaces"  70 with "spaces"  93 with "spaces"
26 with "spaces"   49 with "spaces"  71 with "spaces"  94 with "spaces"
27 with "spaces"   5 with "spaces"   72 with "spaces"  95 with "spaces"
28 with "spaces"   50 with "spaces"  73 with "spaces"  96 with "spaces"
29 with "spaces"   51 with "spaces"  74 with "spaces"  97 with "spaces"
3 with "spaces"    52 with "spaces"  75 with "spaces"  98 with "spaces"
30 with "spaces"   53 with "spaces"  76 with "spaces"  99 with "spaces"
$  ls | sort -n | xargs -d'\n' sh -c 'set -x; pdftk "${@}" cat output combinewd2.pdf' "${0}"
+ pdftk '1 with "spaces"' '2 with "spaces"' '3 with "spaces"' '4 with "spaces"' '5 with "spaces"' '6 with "spaces"' '7 with "spaces"' '8 with "spaces"' '9 with "spaces"' '10 with "spaces"' '11 with "spaces"' '12 with "spaces"' '13 with "spaces"' '14 with "spaces"' '15 with "spaces"' '16 with "spaces"' '17 with "spaces"' '18 with "spaces"' '19 with "spaces"' '20 with "spaces"' '21 with "spaces"' '22 with "spaces"' '23 with "spaces"' '24 with "spaces"' '25 with "spaces"' '26 with "spaces"' '27 with "spaces"' '28 with "spaces"' '29 with "spaces"' '30 with "spaces"' '31 with "spaces"' '32 with "spaces"' '33 with "spaces"' '34 with "spaces"' '35 with "spaces"' '36 with "spaces"' '37 with "spaces"' '38 with "spaces"' '39 with "spaces"' '40 with "spaces"' '41 with "spaces"' '42 with "spaces"' '43 with "spaces"' '44 with "spaces"' '45 with "spaces"' '46 with "spaces"' '47 with "spaces"' '48 with "spaces"' '49 with "spaces"' '50 with "spaces"' '51 with "spaces"' '52 with "spaces"' '53 with "spaces"' '54 with "spaces"' '55 with "spaces"' '56 with "spaces"' '57 with "spaces"' '58 with "spaces"' '59 with "spaces"' '60 with "spaces"' '61 with "spaces"' '62 with "spaces"' '63 with "spaces"' '64 with "spaces"' '65 with "spaces"' '66 with "spaces"' '67 with "spaces"' '68 with "spaces"' '69 with "spaces"' '70 with "spaces"' '71 with "spaces"' '72 with "spaces"' '73 with "spaces"' '74 with "spaces"' '75 with "spaces"' '76 with "spaces"' '77 with "spaces"' '78 with "spaces"' '79 with "spaces"' '80 with "spaces"' '81 with "spaces"' '82 with "spaces"' '83 with "spaces"' '84 with "spaces"' '85 with "spaces"' '86 with "spaces"' '87 with "spaces"' '88 with "spaces"' '89 with "spaces"' '90 with "spaces"' '91 with "spaces"' '92 with "spaces"' '93 with "spaces"' '94 with "spaces"' '95 with "spaces"' '96 with "spaces"' '97 with "spaces"' '98 with "spaces"' '99 with "spaces"' '100 with "spaces"' cat output combinewd2.pdf
_

すべての引数が正しく引用されています。ファイル名に改行が含まれている場合、これは失敗し、_ls -v_は基本的に_ls | sort -n_であることに注意してください。

11
andrewdotn

これは、スペース、改行、アポストロフィ、引用符を含むファイル名で機能するはずです(これらはすべてUNIXファイルシステムで可能です)。

find . -maxdepth 1 -type f -print0 |
  sort -zn |
  xargs -0 sh -c 'pdftk "$@" cat output combinewd2.pdf' "$0"

単純なファイル名で作業していることがわかっている場合、これは受け入れられた回答と比較してやり過ぎかもしれません。

ただし、将来再び使用するスクリプトを作成する場合は、異常な(しかし有効な)入力に出会ったときに爆発しないことが望ましいです。

これは基本的に、改行ではなくゼロバイトで入力ファイルを終了する andrewdotn の回答の改作であり、1つ以上の改行文字を含むファイル名を保持します。

それぞれのオプション-print0-zおよび-0各プログラムに、入出力をゼロバイトで区切る必要があることを伝えます。 3つの異なるプログラム、3つの異なる引数!

6
joeytwiddle

私が見つけた最も直感的な方法は、

  • 最初に-I {}と "echo"を使用してコマンドを作成します。
  • 次に、「bash」を使用してコマンドを実行します(シェルスクリプトを実行している場合と同様)。

拡張子を「.txt」から「.txt.json」に変更する例を次に示します。

find .|grep txt$|xargs -I{} echo "mv {} {}.json"|bash

.txtの名前を.jsonに変更する少し高度な例(.txt拡張子の削除)

find $PWD|grep txt$|cut -d"." -f1|xargs -I{} echo "mv {}.txt {}.json"|bash

以前、すべてのファイルに文字列「End of File」を追加する必要がありました。

find .|grep txt|xargs -I{} echo "echo End of File >> {}"|bash

正しく実行すれば、xargsはすべてのコマンドの王様です!

4
Thyag

ここでの問題は、xargsが-iおよび{}を使用してコマンドの途中に個々の引数を置くことができる一方で、複数の引数に対してこれを行うことを拒否することです。これは私たちに多くのトラブルを引き起こしている見落としのようです!

上記の解決策とは別に、別の方法として、ファイルの後に来る引数をファイルリストの最後に追加するだけです。

(
  ls | sort -n
  echo cat
  echo output
  echo combinewd2.pdf
) | xargs -d'\n' pdftk

このアプローチ改行を含むファイル名では機能しません。そのまれなケースでは、他の回答で提供されているように、ゼロバイトで終了する行をxargsに渡す必要があります。

1
joeytwiddle

これは同じ問題に対して私がやったことであり、実際に生産で使用しています:

cat chapter_order-pdf-sample.txt | xargs -J % pdftk % cat output sample.pdf
0
brian d foy