388
cat a.txt | xargs -I % echo %

上記の例では、xargsはecho %コマンド引数を取ります。ただし、場合によっては、引数を処理するために1つではなく複数のコマンドが必要になります。例えば:

cat a.txt | xargs -I % {command1; command2; ... }

しかし、xargsはこの形式を受け入れません。私が知っている解決策の1つは、コマンドをラップする関数を定義できることですが、それは複雑なので避けたいと思います。より良い解決策はありますか?

4

11 に答える 11

511
cat a.txt | xargs -d $'\n' sh -c 'for arg do command1 "$arg"; command2 "$arg"; ...; done' _

...または、猫の役に立たない使用なしで:

<a.txt xargs -d $'\n' sh -c 'for arg do command1 "$arg"; command2 "$arg"; ...; done' _

より細かい点のいくつかを説明するには:

  • "$arg"代わりに使用する%(およびコマンドラインに存在しない-I)のxargsは、セキュリティ上の理由からです。shコードに置き換える代わりに、コマンドライン引数リストにデータを渡すと、データに含まれる可能性のあるコンテンツ$(rm -rf ~)(悪意のある例)コードとして実行されないようにします。

  • 同様に、の使用は、入力ファイルの各行を個別のデータ項目として扱う-d $'\n'GNU拡張機能です。xargsが読み取るストリームにシェルのような(ただしシェル互換ではない)解析を適用しようとするのを防ぐには、xargsこれまたは(改行ではなくNULを想定)のいずれかが必要です。(GNU xargsがない場合は、を使用せずに行指向の読み取りを取得できます)。-0tr '\n' '\0' <a.txt | xargs -0 ...-d

  • はの_プレースホルダーであり、 become以降$0によって追加された他のデータ値は、ループが繰り返すデフォルトの値のセットになります。xargs$1for

于 2011-08-05T15:41:33.477 に答える
48

使用できます

cat file.txt | xargs -i  sh -c 'command {} | command2 {} && command3 {}'

{}=テキストファイルの各行の変数

于 2014-02-14T05:20:17.520 に答える
43

GNU Parallelを使用すると、次のことができます。

cat a.txt | parallel 'command1 {}; command2 {}; ...; '

詳細については、紹介動画をご覧ください:https ://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

セキュリティ上の理由から、パッケージマネージャーを使用してインストールすることをお勧めします。ただし、それができない場合は、この10秒のインストールを使用できます。

10秒のインストールでは、完全なインストールが試行されます。それが失敗した場合は、個人的なインストール。それが失敗した場合は、最小限のインストール。

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 883c667e01eed62f975ad28b6d50e22a
12345678 883c667e 01eed62f 975ad28b 6d50e22a
$ md5sum install.sh | grep cc21b4c943fd03e93ae1ae49e28573c0
cc21b4c9 43fd03e9 3ae1ae49 e28573c0
$ sha512sum install.sh | grep da012ec113b49a54e705f86d51e784ebced224fdf
79945d9d 250b42a4 2067bb00 99da012e c113b49a 54e705f8 6d51e784 ebced224
fdff3f52 ca588d64 e75f6033 61bd543f d631f592 2f87ceb2 ab034149 6df84a35
$ bash install.sh
于 2012-10-05T14:40:17.537 に答える
27

私はドライランモード(なし| sh)を可能にするスタイルを好みます:

cat a.txt | xargs -I % echo "command1; command2; ... " | sh

パイプでも機能します:

cat a.txt | xargs -I % echo "echo % | cat " | sh
于 2017-09-08T07:35:59.003 に答える
26

これは、xargsもcatも使用しない別のアプローチです。

while read stuff; do
  command1 "$stuff"
  command2 "$stuff"
  ...
done < a.txt
于 2011-08-05T15:51:14.797 に答える
19

私が行うことの1つは、この関数を.bashrc/.profileに追加することです。

function each() {
    while read line; do
        for f in "$@"; do
            $f $line
        done
    done
}

その後、あなたは次のようなことをすることができます

... | each command1 command2 "command3 has spaces"

これは、xargsや-execよりも冗長ではありません。また、その動作が必要な場合は、関数を変更して、コマンドの任意の場所にある読み取り値をそれぞれに挿入することもできます。

于 2012-09-28T01:24:22.503 に答える
19

これが最も安全なバージョンのようです。

tr '[\n]' '[\0]' < a.txt | xargs -r0 /bin/bash -c 'command1 "$@"; command2 "$@";' ''

-0削除trしてリダイレクトに置き換えることができます(またはファイルを代わりにnullで区切られたファイルに置き換えることができます)。これは主に出力で使用するため、主にそこにありますxargs)(これは拡張子のないバージョンにも関連する可能性があります)find-print0xargs-0

argsは、実行時にパラメーターを配列としてシェルに渡すため、安全です。シェルは(少なくともbash)、すべてがを使用して取得されたときに、変更されていない配列として他のプロセスにそれらを渡します。["$@"][1]

を使用...| xargs -r0 -I{} bash -c 'f="{}"; command "$f";' ''する場合、文字列に二重引用符が含まれていると、割り当ては失敗します。-iこれは、またはを使用するすべてのバリアントに当てはまります-I。(文字列に置き換えられるため、入力データに予期しない文字(引用符、バッククォート、ドル記号など)を挿入することで、いつでもコマンドを挿入できます)

コマンドが一度に1つのパラメーターしか受け取れない場合:

tr '[\n]' '[\0]' < a.txt | xargs -r0 -n1 /bin/bash -c 'command1 "$@"; command2 "$@";' ''

または、プロセスがやや少なくなります。

tr '[\n]' '[\0]' < a.txt | xargs -r0 /bin/bash -c 'for f in "$@"; do command1 "$f"; command2 "$f"; done;' ''

拡張機能を備えたGNUxargsまたは別の-Pプロセスがあり、32個のプロセスを並行して実行したい場合、各プロセスには、コマンドごとに10個以下のパラメーターがあります。

tr '[\n]' '[\0]' < a.txt | xargs -r0 -n10 -P32 /bin/bash -c 'command1 "$@"; command2 "$@";' ''

これは、入力内の特殊文字に対して堅牢である必要があります。(入力がnullで区切られている場合。)tr一部の行に改行が含まれている場合、バージョンは無効な入力を取得しますが、改行で区切られたファイルでは避けられません。

の空白の最初のパラメータbash -cはこれによるものです:(bashマニュアルページから)(ありがとう@clacke)

-c   If the -c option is present, then  commands  are  read  from  the  first  non-option  argument  com‐
     mand_string.   If there are arguments after the command_string, the first argument is assigned to $0
     and any remaining arguments are assigned to the positional parameters.  The assignment  to  $0  sets
     the name of the shell, which is used in warning and error messages.
于 2018-07-12T12:03:04.603 に答える
10

私のために働く別の可能な解決策は次のようなものです-

cat a.txt | xargs bash -c 'command1 $@; command2 $@' bash

最後の「bash」に注意してください-argv[0]としてbashに渡されると思います。この構文にそれがないと、各コマンドの最初のパラメーターが失われます。それはどんな言葉でもかまいません。

例:

cat a.txt | xargs -n 5 bash -c 'echo -n `date +%Y%m%d-%H%M%S:` ; echo " data: " $@; echo "data again: " $@' bash
于 2014-02-12T07:54:56.490 に答える
3

これに対する私の現在のBKMは

... | xargs -n1 -I % perl -e 'system("echo 1 %"); system("echo 2 %");'

これがperlを使用しているのは残念ですが、これはbashよりもインストールされる可能性が低くなります。しかし、それは受け入れられた答えよりも多くの入力を処理します。(私はperlに依存しないユビキタスバージョンを歓迎します。)

@KeithThompsonの提案

 ... | xargs -I % sh -c 'command1; command2; ...'

素晴らしいです-入力にシェルコメント文字#が含まれていない限り、最初のコマンドの一部と2番目のコマンドのすべてが切り捨てられます。

入力がlsやfindなどのファイルシステムリストから派生し、エディターが名前に#を含む一時ファイルを作成する場合、ハッシュ#は非常に一般的です。

問題の例:

$ bash 1366 $>  /bin/ls | cat
#Makefile#
#README#
Makefile
README

おっと、ここに問題があります:

$ bash 1367 $>  ls | xargs -n1 -I % sh -i -c 'echo 1 %; echo 2 %'
1
1
1
1 Makefile
2 Makefile
1 README
2 README

ああ、それは良いです:

$ bash 1368 $>  ls | xargs -n1 -I % perl -e 'system("echo 1 %"); system("echo 2 %");'
1 #Makefile#
2 #Makefile#
1 #README#
2 #README#
1 Makefile
2 Makefile
1 README
2 README
$ bash 1369 $>  
于 2016-01-24T16:47:26.500 に答える
2

これを試して:

git config --global alias.all '!f() { find . -d -name ".git" | sed s/\\/\.git//g | xargs -P10 -I{} git --git-dir={}/.git --work-tree={} $1; }; f'

10個のスレッドを並行して実行し、フォルダー構造内のすべてのリポジトリに対して必要なgitコマンドを実行します。リポジトリの深さが1レベルかnレベルかに関係なく。

例えば:git all pull

于 2020-09-14T10:33:59.710 に答える
0

私はその問題を解決するのに良い考えを持っています。カンマを書くだけで、次のmcmdことができます

find . -type f | xargs -i mcmd echo {} @@ cat {} @pipe sed -n '1,3p'

内容は次のmcmdとおりです。

echo $* | sed -e 's/@@/\n/g' -e 's/@pipe/|/g' | csh
于 2021-04-30T03:30:58.787 に答える