让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时需要考虑两个问题:
- 如何将投入分解为“论据”; 和
- 一次有多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 \;