让xargs为每一行input执行一次命令

我怎样才能让xargs为给定的每一行input执行一次命令? 它的默认行为是块行和执行一次,传递多个行到每个实例。

来自http://en.wikipedia.org/wiki/Xargs :

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

在这个例子中,find使用一长串文件名来inputxargs。 然后,xargs将这个列表拆分成子列表,并为每个子列表调用rm一次。 这比这个function相当的版本更有效率:

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. 

在我看来,所有现有的答案都是错误的,包括标记为正确的答案。 这源于这个问题含糊不清。

总结:如果你想执行命令“对于给定的每一行只input一次” ,把整行(不带换行符)作为单个参数传递给命令那么这是与UNIX兼容的最佳方法:

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

GNU xargs可能有也可能没有有用的扩展,允许你tr ,但是它们在OS X和其他UNIX系统上不可用。

现在为了长久的解释…


使用xargs时需要考虑两个问题:

  1. 如何将投入分解为“论据”; 和
  2. 一次有多less个parameter passing子命令。

为了testingxargs的行为,我们需要一个实用程序来显示执行的次数以及多less个参数。 我不知道是否有一个标准的工具来做到这一点,但我们可以很容易地在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" 

现在,如果原来的问题真的是关于第二点(正如我认为的那样,在阅读了几遍之后),那么这个问题应该是这样读的(改变为粗体):

我怎样才能让xargs为给定的每个input参数精确地执行一次? 其默认行为是将input分为参数,尽可能less地执行命令,将多个参数传递给每个实例。

那么答案是-n 1

我们来比较xargs的默认行为,它将input分割为空白,并尽可能less地调用命令:

 $ 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" 

另一方面,如果原来的问题是关于第一点的input分裂,那就是这样读的(很多人来这里似乎都认为是这样,或者混淆了这两个问题):

我怎样才能使xargs执行命令给定的每一行input只有一个参数 它的默认行为是块空白周围的行。

那么答案就更加微妙了。

有人会认为-L 1可能有帮助,但事实certificate它不会改变参数parsing。 它只对每个input行执行一次命令,其input行上的参数数量与之相同:

 $ 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" 

显然, -L并不是要改变xargs将input分解为参数的方式。

以跨平台方式(不包括GNU扩展名)这样做的唯一参数是-0 ,它将input拆分为NUL个字节。

然后,这只是在tr的帮助下将换行符转换为NUL的问题:

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

现在参数parsing看起来很好,包括尾随的空白。

最后,如果将此技术与-n 1结合使用,则无论您有什么input,都可以得到每个input行的一个命令执行,这可能是查看原始问题的另一种方式(可能是最直观的,标题为):

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

如果你想运行命令来查找每一行(即结果),那么你需要什么xargs的?

尝试:

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

其中文字{}被replace为文件名和文字\; 需要知道自定义命令在那里结束。

编辑:

(在你的问题的编辑澄清你知道关于-exec

man xargs

-L 最大线
每个命令行最多使用最多行非空白input行。 尾随空白会导致input行在下一个input行上被逻辑地继续。 意味着-x。

请注意,如果您使用xargs以空格结尾的文件名会导致麻烦:

 $ mkdir /tmp/bax; cd /tmp/bax $ touch a\ bc\ 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 

我不喜欢-L答案,因为它不处理带有空格的文件,这是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 

更好的解决scheme是使用tr将换行符转换为空( \0 )字符,然后使用xargs -0参数。

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

使用-L另一个问题是它不允许每个xargs命令调用多个参数。 例如,目前被接受的解决scheme会为每一个执行人员的每一行调用/bin/rm 。 通过使用tr命令,可以使用-n来限制每次调用实用程序时从input中读取的行数。

 find . -name \*.java | tr '\n' '\0' | xargs -0 wc 

这也允许您将中断转换为空值之前过滤find的输出。

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

另一种select…

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

是你所需要的全部。

以下命令将find/path所有文件(-type f),然后使用cp将它们复制到当前文件夹中。 请注意,如果-I %指定cp命令行中的占位符字符,则可以在文件名后面放置参数。

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

用xargs(GNU findutils)testing4.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. 

这两种方式也起作用,并且会为其他不使用find的命令起作用!

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

示例用例:

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

将删除此目录下的所有pyc文件,即使pyc文件包含空格。

看起来我没有足够的声望来给Tobia上面的答案添加评论,所以我添加了这个“答案”来帮助那些想在Windows平台上以相同方式尝试xargs的人。

这里是一个windowsbatch file,和Tobia快速编码的“show”脚本一样:

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

在你的例子中,将find的输出传递给xargs的要点在于find的-exec选项的标准行为是为每个find的文件执行一次命令。 如果你使用find,而你想要它的标准行为,那么答案很简单 – 不要使用xargs来开始。

在当前或子文件夹的每个build.xml上执行ant任务clean-all。

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