当前位置:  开发笔记 > 编程语言 > 正文

使xargs为每行输入执行一次命令

如何解决《使xargs为每行输入执行一次命令》经验,为你挑选了6个好方法。

如何为每个给定的输入行使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"标志.我只是引用另一个资源的说明性示例.



1> Draemon..:

只有在输入中没有空格时,以下内容才有效:

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.


如果省略`MAX-LINES`,则默认为1,因此`xargs -l`就足够了.见`info xargs`.
对我而言,它可以像你给出的那个"xargs -n 1"那样显示"参数列表太长".
这是错的.`-L 1`不回答原始问题,而`-n 1`仅在一种可能的解释中这样做.请参阅下面的长答案.
@Wernight:" - n1"不会为每个输入行提供1次调用.也许你的输入线太长了.演示:`echo"foo bar"| xargs -n1 echo`.因此,如果你管道像'ls'这样的东西,它将无法很好地处理空间.
@Tobia:它回答了原始问题,这是一个非常具体的输入行.这正是`-L 1`的作用.对我来说,OP似乎显然试图避免默认的分块行为,因为这被接受了,我认为我是对的.你的答案解决了一个稍微不同的用例,你也想要分块行为.

2> Tobia..:

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

简介:   如果要执行命令"对于给定的每一行输入只执行一次",将整行(不带换行符)作为单个参数传递给命令,那么这是与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" 


@olala`-L`每个输入行执行一次命令(但是一行的一个空格将它连接到下一行,并且该行仍然根据空格分成参数); 而`-n`每个输入参数执行一次命令.如果计算输出示例中的` - >`的数量,那么这些是执行脚本`./ show`的次数.
*GNU`xargs`可能有也可能没有有用的扩展,允许你取消`tr`*它有一个非常有用的扩展; 来自`xargs --help` - *-d, - delimiter =输入流中的CHARACTER项由CHARACTER分隔,而不是由空格分隔; 禁用报价和反斜杠处理以及逻辑EOF处理*

3> tzot..:

如果你想为来自的每一行(即结果)运行命令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



4> Gray..:

如何为每个给定的输入行使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



5> 小智..:

另一种选择......

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



6> 小智..:

这两种方式也可以使用,并且可以用于其他未使用find的命令!

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

示例用例:

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

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

推荐阅读
Gbom2402851125
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有