入力行ごとにxargsにコマンドを1回実行させる


341

与えられた入力の各行に対して、xargsにコマンドを1回だけ実行させるにはどうすればよいですか?デフォルトの動作では、行を分割してコマンドを1回実行し、各インスタンスに複数の行を渡します。

http://en.wikipedia.org/wiki/Xargsから:

/ path -type f -print0 | xargs -0 rm

この例では、findはxargsの入力にファイル名の長いリストをフィードします。次に、xargsはこのリストをサブリストに分割し、サブリストごとにrmを1回呼び出します。これは、この機能的に同等のバージョンよりも効率的です。

/ path -type f -exec rm '{}'を検索します\;

findに "exec"フラグがあることを知っています。私は別のリソースからの実例を引用しています。


4
あなたが提供する例では、find /path -type f -deleteさらに効率的です:)
tzot

xargsを使用しないようにしてください...
Naib

6
OP、この質問は非常に古いことは知っていますが、それでもGoogleで表示され、私見では受け入れられた答えが間違っています。以下の私の長い回答を参照してください。
Tobia

受け入れを@Tobiaの回答に切り替えることを検討してください。受け入れられた回答は名前のスペースを処理せず、xargsの主な機能の1つであるxargsコマンドへの複数の引数を許可しません。
グレイ

回答:


391

以下は、入力にスペースがない場合にのみ機能します。

xargs -L 1
xargs --max-lines=1 # synonym for the -L option

manページから:

-L max-lines
          Use at most max-lines nonblank input lines per command line.
          Trailing blanks cause an input line to be logically continued  on
          the next input line.  Implies -x.

13
私にとってはxargs -n 1、あなたが与えたものが「引数リストが長すぎる」ことを示しているように、それはうまくいきます。
Wernight

19
場合はMAX-LINES1にデフォルトで省略され、これxargs -lは十分です。を参照してくださいinfo xargs
トール

3
@Wernight: "-n1"は、入力行ごとに1回の呼び出しを行いません。入力行が長すぎる可能性があります。デモ:echo "foo bar" | xargs -n1 echo。したがって、「ls」などのパイプを使用すると、スペースをうまく処理できません。
gatoatigrado 2014

8
これは間違っています。-L 1元の質問には答えず-n 1、可能な解釈の1つだけで答えます。以下の私の長い答えを見てください。
トビア

2
@Tobia:元の質問に答えます。これは、特に入力行に関する質問でした。それがまさにその通り-L 1です。私にとって、OPは明らかにデフォルトのチャンク動作を回避しようとしているようで、これが受け入れられたので、私は正しいと思います。答えは、チャンク動作も必要とする、少し異なるユースケースに対応します。
ドラえもん2015年

206

正しいとマークされているものを含め、このページの既存の回答はすべて間違っているようです。それは質問が曖昧に表現されているという事実に由来します。

概要:   コマンドを「指定された入力行ごとに1回だけ」実行し、全体(改行なし)を単一の引数としてコマンドに渡す場合、これはUNIX互換の最良の方法です。

... | tr '\n' '\0' | xargs -0 -n1 ...

GNUにxargsは、を廃止できる便利な拡張機能がある場合とないtr場合がありますが、OS Xやその他のUNIXシステムでは使用できません。

長い説明のために…


xargsを使用する際に考慮すべき2つの問題があります。

  1. 入力を「引数」に分割する方法。そして
  2. 一度に子コマンドを渡す引数の数。

xargsの動作をテストするには、それが実行された回数と引数の数を示すユーティリティが必要です。それを行うための標準的なユーティリティがあるかどうかはわかりませんが、bashで非常に簡単にコーディングできます。

#!/bin/bash
echo -n "-> "; for a in "$@"; do echo -n "\"$a\" "; done; echo

show現在のディレクトリに保存して実行可能にすると、次のようになります。

$ ./show one two 'three and four'
-> "one" "two" "three and four" 

さて、元の質問が本当に上記のポイント2に関するものである場合(私が思うに、数回読んだ後)、次のように読む必要があります(太字の変更):

与えられた入力の各引数に対してxargsにコマンドを正確に一度だけ実行させるにはどうすればよいですか?そのデフォルトの動作では、入力を引数に分割し、コマンドを可能な限り数回実行して、各インスタンスに複数の引数を渡します。

次に答えは -n 1です。

xargsのデフォルトの動作を比較してみましょう。これは、入力を空白で分割し、コマンドを可能な限り数回呼び出します。

$ echo one two 'three and four' | xargs ./show 
-> "one" "two" "three" "and" "four" 

およびその動作-n 1

$ echo one two 'three and four' | xargs -n 1 ./show 
-> "one" 
-> "two" 
-> "three" 
-> "and" 
-> "four" 

一方、元の質問がポイント1に関するものだった場合、入力の分割と次のように読む必要があります(ここに来る多くの人がそうだと思うか、2つの問題を混同しているようです)。

xargsに、指定された入力行ごとに1つの引数指定してコマンド実行させるにはどうすればよいですか?そのデフォルトの動作は、空白の周りの行を分割することです。

それから答えはもっと微妙です。

-L 1それは助けになるかもしれないと思う人もいるでしょうが、それは引数の解析を変更しないことがわかりました。入力行ごとに1回だけコマンドを実行し、その入力行にあるのと同じ数の引数を使用します。

$ echo $'one\ntwo\nthree and four' | xargs -L 1 ./show 
-> "one" 
-> "two" 
-> "three" "and" "four" 

それだけでなく、行が空白で終わる場合、次の行に追加されます。

$ echo $'one \ntwo\nthree and four' | xargs -L 1 ./show 
-> "one" "two" 
-> "three" "and" "four" 

明らかに、-Lxargsが入力を引数に分割する方法を変更することではありません。

クロスプラットフォーム方式(GNU拡張を除く)でそうする唯一の引数は-0、入力をNULバイトに分割することです。

次に、改行をNULに変換するだけですtr

$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show 
-> "one " "two" "three and four" 

これで、引数の解析は、末尾の空白も含めて問題なく見えます。

最後に、この手法をと組み合わせると-n 1、入力が何であっても、入力行ごとに1つのコマンドが実行されます。これは、元の質問を調べる別の方法となる場合があります(タイトルを指定すると、おそらく最も直感的です)。

$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show 
-> "one " 
-> "two" 
-> "three and four" 

これがより良い答えのように見えます。ただし、-Lと-nの違いはまだよくわかりません...もう少し説明できますか?
オララ

5
@olala -Lは、入力行ごとに1回コマンドを実行します(ただし、行末のスペースは次の行に結合しますが、行は空白に従って引数に分割されます)。while -nは、入力引数ごとにコマンドを1回実行します。->出力例の数を数えると、スクリプト./showが実行された回数になります。
トビア2016年

そうですか!行末のスペースが次の行に結合されることに気づかなかった。ありがとう!
オララ

4
GNU xargsは、あなたがそれをやめることを可能にする有用な拡張機能を持っているかもしれないし、持っていないかもしれませんtr。from xargs --help-d、
Piotr Dobrogost

この回答はに関して混乱しているよう-Lです。-L1行あたりのスクリプトの実行回数は示されていません。一度に消費する入力データの行数が示されています。
Moberg

22

からのすべての行(つまり結果)に対してコマンドを実行する場合find、何が必要xargsですか?

試してください:

find パス -type f -exec あなたのコマンド {} \;

ここで、リテラル{}はファイル名に置き換えられ、カスタムコマンドがそこで終了することを知るに\;はリテラルが必要ですfind

編集:

(あなたが知っていることを明確にする質問の編集後-exec

からman xargs

-L max-linesコマンドラインごとに最大max-linesの空白以外の入力行を
使用します。末尾の空白は、入力行を次の入力行に論理的に継続させます。-xを意味します。

空白で終わるファイル名は、以下を使用する場合に問題を引き起こすことに注意してくださいxargs

$ mkdir /tmp/bax; cd /tmp/bax
$ touch a\  b c\  c
$ find . -type f -print | xargs -L1 wc -l
0 ./c
0 ./c
0 total
0 ./b
wc: ./a: No such file or directory

だから、気にしない場合は-exec、あなたに、オプションより有効に利用する-print0-0

$ find . -type f -print0 | xargs -0L1 wc -l
0 ./c
0 ./c
0 ./b
0 ./a

17

与えられた入力の各行に対して、xargsにコマンドを1回だけ実行させるにはどうすればよいですか?

-L 1簡単な解決策ですが、ファイルにスペースが含まれている場合は機能しません。これは、findの-print0引数の重要な機能です。空白文字ではなく「\ 0」文字で引数を区切ります。次に例を示します。

echo "file with space.txt" | xargs -L 1 ls
ls: file: No such file or directory
ls: with: No such file or directory
ls: space.txt: No such file or directory

より良い解決策は、を使用trして改行をnull(\0)文字に変換し、xargs -0引数を使用することです。次に例を示します。

echo "file with space.txt" | tr '\n' '\0' | xargs -0 ls
file with space.txt

その後、呼び出しの数を制限する必要がある場合は、-n 1引数を使用して、入力ごとにプログラムを1回呼び出すことができます。

echo "file with space.txt" | tr '\n' '\0' | xargs -0 -n 1 ls

これにより、ブレークをnull 変換するにfindの出力をフィルタリングすることもできます。

find . -name \*.xml | grep -v /target/ | tr '\n' '\0' | xargs -0 tar -cf xml.tar

1
2番目のコードブロックtr '\ n' '\ 0 \ => tr' \ n '' \ 0 'に構文エラーがあります。これを修正しようとしましたが、「編集内容は6文字以上である必要があります」(これは私の変更が6文字未満だったのでgitがコミットを拒否するので愚かです)
htaccess

1
これはどういう意味ですか:「使用に関するもう1つの問題-Lは、xargsコマンド呼び出しごとに複数の引数を許可しないことです。」?
Moberg

その無関係な情報@Mobergを削除するために、回答を改善しました。
グレイ


9

これらの2つの方法も機能し、find!を使用していない他のコマンドでも機能します。

xargs -I '{}' rm '{}'
xargs -i rm '{}'

使用例:

find . -name "*.pyc" | xargs -i rm '{}'

pycファイルにスペースが含まれている場合でも、このディレクトリの下にあるすべてのpycファイルが削除されます。


これにより、最適ではない要素ごとに1つのユーティリティコールが発行されます。
グレイ

7
find path -type f | xargs -L1 command 

は、あなたが必要とすることすべてです。


4

次のコマンドは、すべてのファイル(-fタイプ)を検索し、/pathそれを使用cpして現在のフォルダーにコピーします。if -I %を使用してcpコマンドラインでプレースホルダー文字を指定し、ファイル名の後に引数を配置できるようにします。

find /path -type f -print0 | xargs -0 -I % cp % .

xargs(GNU findutils)4.4.0でテスト済み


2

--max-linesまたは--max-argsフラグをそれぞれ使用して、行数または引数(各引数の間にスペースがある場合)を制限できます。

  -L max-lines
         Use at most max-lines nonblank input lines per command line.  Trailing blanks cause an input line to be logically continued on the next  input
         line.  Implies -x.

  --max-lines[=max-lines], -l[max-lines]
         Synonym  for  the -L option.  Unlike -L, the max-lines argument is optional.  If max-args is not specified, it defaults to one.  The -l option
         is deprecated since the POSIX standard specifies -L instead.

  --max-args=max-args, -n max-args
         Use at most max-args arguments per command line.  Fewer than max-args arguments will be used if the size (see  the  -s  option)  is  exceeded,
         unless the -x option is given, in which case xargs will exit.

0

上記のTobiaの回答にコメントを追加するのに十分な評判がないようです。この「回答」を追加xargsして、Windowsプラットフォームで同じ方法で実験したい人のために役立てます。

これは、Tobiaの迅速にコード化された「表示」スクリプトと同じことを行うWindowsバッチファイルです。

@echo off
REM
REM  cool trick of using "set" to echo without new line
REM  (from:  http://www.psteiner.com/2012/05/windows-batch-echo-without-new-line.html)
REM
if "%~1" == "" (
    exit /b
)

<nul set /p=Args:  "%~1"
shift

:start
if not "%~1" == "" (
    <nul set /p=, "%~1"
    shift
    goto start
)
echo.

0

ファイル内にスペースがあっても、@ Draemonの回答は「-0」で正しいようです。

xargsコマンドを試してみたところ、「-0」は「-L」と完全に連動することがわかりました。スペースも処理されます(入力がnullで終了した場合)。次に例を示します。

#touch "file with space"
#touch "file1"
#touch "file2"

次の例では、nullを分割し、リストの各引数に対してコマンドを実行します。

 #find . -name 'file*' -print0 | xargs -0 -L1
./file with space
./file1
./file2

そのため-L1、 "-0"と一緒に使用すると、ヌルで終了する各文字で引数が実行されます。違いを確認するには:

 #find . -name 'file*' -print0 | xargs -0 | xargs -L1
 ./file with space ./file1 ./file2

これでも一度実行されます:

 #find . -name 'file*' -print0  | xargs -0  | xargs -0 -L1
./file with space ./file1 ./file2

「-L」はnullバイトで分割されないため、コマンドは1回実行されます。機能するには、「-0」と「-L」の両方を指定する必要があります。


-3

あなたの例では、findの出力をxargsにパイプするポイントは、findの-execオプションの標準的な動作は、見つかったファイルごとにコマンドを1回実行することです。findを使用していて、その標準的な動作が必要な場合、答えは簡単です。最初にxargsを使用しないでください。


実際、私がOPの編集から示唆できることは、入力データがとは何の関係もないfindということです-exec。そのため、彼らはこのオプションを好まないのです。
tzot 2009

-3

現在またはサブフォルダーのすべてのbuild.xmlでant task clean-allを実行します。

find . -name 'build.xml' -exec ant -f {} clean-all \;

誰もがantインストールしたわけではありません。
グレイ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.