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

时间:2008-10-13 22:31:25

标签: xargs

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

13 个答案:

答案 0 :(得分:356)

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

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 :(得分:162)

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

摘要:如果要为给定的每一行输入执行一次命令,“将整行(不带换行符)传递给命令一个单个参数,然后这是与UNIX兼容的最佳方法:

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

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

现在有很长的解释......


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

  1. 如何将输入分成“参数”;和
  2. 一次传递子命令的参数数量。
  3. 为了测试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字节。

    然后,只需要在tr的帮助下将换行符翻译成NUL:

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

答案 2 :(得分:22)

如果要运行来自find每个行(即结果)的命令,那么您需要xargs为什么?

尝试:

find 路径 -type f -exec 你的命令 {} \;

其中文字{}被文件名替换,\;需要文字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

答案 3 :(得分:14)

  

如何让xargs对给定的每一行输入执行一次命令?

我没有使用-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将换行符转换为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 /workspace/ | tr '\n' '\0' | xargs -0 tar -cf xml.tar

答案 4 :(得分:10)

另一种选择......

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

答案 5 :(得分:4)

find path -type f | xargs -L1 command 

就是你所需要的一切。

答案 6 :(得分:4)

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

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

示例用例:

find . -name "*.pyc" | xargs -i rm '{}
即使pyc文件包含空格,

也会删除此目录下的所有pyc文件。

答案 7 :(得分:3)

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

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

使用xargs(GNU findutils)4.4.0进行测试

答案 8 :(得分:1)

您可以分别使用--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.

答案 9 :(得分:0)

我似乎没有足够的声誉向Tobia's answer above添加评论,所以我添加了这个“答案”,以帮助我们这些想要以同样的方式试验xargs的人Windows平台。

这是一个Windows批处理文件,与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.

答案 10 :(得分:0)

@Draemon的答案似乎与“ -0”正确,即使文件中有空格。

我正在尝试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

因此,-L1如果与“ -0”一起使用,将对每个以null结尾的字符执行自变量。要查看差异,请尝试:

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

这将执行一次:

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

该命令将执行一次,因为“ -L”现在不会在空字节上分割。您需要同时提供“ -0”和“ -L”才能正常工作。

答案 11 :(得分:-2)

在您的示例中,将find的输出管道输出到xargs的点是find的-exec选项的标准行为是为每个找到的文件执行一次命令。如果你正在使用find,并且你想要它的标准行为,那么答案很简单 - 不要使用xargs开头。

答案 12 :(得分:-3)

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

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