如何为每个给定的输入行使xargs执行一次命令?它的默认行为是将行块化并执行一次命令,将多行传递给每个实例.
来自http://en.wikipedia.org/wiki/Xargs:
find/path -type f -print0 | xargs -0 rm
在此示例中,查找使用长文件名列表输入xargs.然后xargs将此列表拆分为子列表,并为每个子列表调用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.
在我看来,这个页面上的所有现有答案都是错误的,包括标记为正确的答案.这源于这个问题含糊不清的事实.
简介: 如果要执行命令"对于给定的每一行输入只执行一次",将整行(不带换行符)作为单个参数传递给命令,那么这是与UNIX兼容的最佳方法:
... | tr '\n' '\0' | xargs -0 -n1 ...
GNU xargs
可能有也可能没有允许您取消的有用扩展tr
,但它们在OS X和其他UNIX系统上不可用.
现在有很长的解释......
使用xargs时需要考虑两个问题:
它是如何将输入分成"参数"的; 和
一次传递子命令的参数数量.
为了测试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点的输入拆分而且它应该像这样阅读(很多人来到这里似乎认为是这种情况,或者混淆了这两个问题):
我怎样才能让xargs的执行命令与正好一个参数给定输入的每一行?它的默认行为是对空白行周围的行进行分块.
然后答案更微妙.
人们会认为这-L 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"
显然,-L
不是要改变xargs将输入分成参数的方式.
以跨平台方式(不包括GNU扩展)这样做的唯一参数是-0
,它将输入分成NUL字节.
然后,这只是通过以下方式将换行符翻译为NUL tr
:
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show -> "one " "two" "three and four"
现在,参数解析看起来很好,包括尾随空格.
最后,如果你将这种技术结合起来-n 1
,你可以得到每个输入行一个命令执行,无论你有什么输入,这可能是另一种查看原始问题的方式(可能是最直观的,给定标题):
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show -> "one " -> "two" -> "three and four"
如果你想为来自的每一行(即结果)运行命令find
,那么你需要什么xargs
呢?
尝试:
find
你的命令路径-type f -exec
{} \;
文本{}
被文件名替换的位置,\;
需要文字find
才能知道自定义命令在那里结束.
(在你的问题编辑之后澄清你知道的事情-exec
)
来自man xargs
:
-L max-lines每个命令行最多
使用max-lines nonblank输入行.尾随空白导致输入线在下一个输入线上逻辑上继续.意味着-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执行一次命令?
我没有使用-L 1
答案,因为它不处理带有空格的文件,这是一个关键的功能find -print0
.
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
参数为每个输入调用一次程序:
echo "file with space.txt" | tr '\n' '\0' | xargs -0 -n 1 ls
这也允许您在将中断转换为空值之前过滤find的输出.
find . -name \*.xml | grep -v /target/ | tr '\n' '\0' | xargs -0 tar -cf xml.tar
另一种选择......
find /path -type f | while read ln; do echo "processing $ln"; done
这两种方式也可以使用,并且可以用于其他未使用find的命令!
xargs -I '{}' rm '{}' xargs -i rm '{}'
示例用例:
find . -name "*.pyc" | xargs -i rm '{}'
即使pyc文件包含空格,也会删除此目录下的所有pyc文件。