入力の各行に対してxargsにコマンドを1回実行させます

StackOverflow https://stackoverflow.com/questions/199266

  •  11-07-2019
  •  | 
  •  

質問

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

  

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

>      

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

     

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

     

find / path -type f -exec rm '{}' \;

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

役に立ちましたか?

解決

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

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

マニュアルページから:

-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.

他のヒント

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

概要: 与えられた入力の各行に対してコマンド"を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にコマンドを1回だけ実行させるにはどうすればよいですか?デフォルトの動作では、入力を引数にチャンクし、コマンドを可能な限り数回実行し、複数の引数を各インスタンスに渡します。

その答えは -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 

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

$ echo 

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

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

次に、 tr を使用して改行をNULに変換するだけです。

$ echo 

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

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

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

<*>

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

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

次に、 tr を使用して改行をNULに変換するだけです。

<*>

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

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

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

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

次に、 tr を使用して改行をNULに変換するだけです。

<*>

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

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

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

<*>

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

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

次に、 tr を使用して改行をNULに変換するだけです。

<*>

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

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

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

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

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

<*>

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

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

次に、 tr を使用して改行をNULに変換するだけです。

<*>

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

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

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

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

次に、 tr を使用して改行をNULに変換するだけです。

<*>

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

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

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

<*>

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

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

次に、 tr を使用して改行をNULに変換するだけです。

<*>

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

<*>one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show -> "one " -> "two" -> "three and four" one\ntwo\nthree and four' | xargs -L 1 ./show -> "one" -> "two" -> "three" "and" "four"

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

<*>

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

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

次に、 tr を使用して改行をNULに変換するだけです。

<*>

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

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

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

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

次に、 tr を使用して改行をNULに変換するだけです。

<*>

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

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

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

<*>

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

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

次に、 tr を使用して改行をNULに変換するだけです。

<*>

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

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

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

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

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

<*>

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

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

次に、 tr を使用して改行をNULに変換するだけです。

<*>

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

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

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

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

次に、 tr を使用して改行をNULに変換するだけです。

<*>

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

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

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

<*>

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

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

次に、 tr を使用して改行をNULに変換するだけです。

<*>

引数の解析は、末尾の空白も含めて問題なく見えるようになりました。

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

<*>

find からの every 行(つまり結果)のコマンドを実行する場合、 xargs は何のために必要ですか

試してください:

find path -type f -exec your-command {} \;

リテラル {} がファイル名とリテラル \に置き換えられる場所; 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
  

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

-L 1 の回答は使用しません。これは、 find -print0 の重要な機能であるスペースを含むファイルを処理しないためです。

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

より良い解決策は、 tr を使用して改行をヌル( \ 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 . -name \*.xml | grep -v /workspace/ | tr '\n' '\0' | xargs -0 tar -cf xml.tar

別の選択肢...

find /path -type f | while read ln; do echo "processing $ln"; done
find path -type f | xargs -L1 command 

必要なものすべてです。

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

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

ユースケースの例:

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

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

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

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

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

行数または引数(各引数間にスペースがある場合)を制限するには、それぞれ--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.

上記のTobiaの回答にコメントを追加するには評判が足りないようですので、これを追加しています&quot; answer&quot; Windowsプラットフォームで同じ方法で xargs を試してみたい人を支援するため。

これは、Tobiaがすばやくコーディングした「show」と同じことを行う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.

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

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

so -L1 は、&quot; -0&quot;と一緒に使用すると、ヌルで終了する各文字で引数を実行します。違いを確認するには、次を試してください:

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

これも1回実行されます:

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

コマンドは&quot; -L&quot;として1回実行されますnullバイトで分割されなくなりました。 「-0」の両方を指定する必要があります。および「-L」働く。

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

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

find . -name 'build.xml' -exec ant -f {} clean-all \;
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top