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

问题描述 投票:311回答:13

我如何使xargs对给定的每一行输入仅执行一次命令?它的默认行为是对行进行分块并执行一次,将多行传递给每个实例。

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

找到/ path -type f -print0 | xargs -0 rm

在此示例中,find为xargs的输入提供了很长的文件名列表。然后,xargs将此列表拆分为子列表,并为每个子列表调用rm一次。这比功能上等效的版本更有效:

找到/ path -type f -exec rm'{}'\;

我知道查找具有“ exec”标志。我只是引用另一个资源中的说明性示例。

xargs
13个回答
367
投票

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

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.

0
投票
[我似乎没有足够的声誉在Tobia's answer above上添加评论,所以我添加此“答案”来帮助希望在Windows平台上以相同方式尝试xargs的我们这些人。

这里是Windows批处理文件,与Tobia快速编码的“显示”脚本具有相同的作用:


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

我正在尝试xargs命令,但发现“ -0”与“ -L”完美配合。即使空格也被处理(如果输入为null终止)。以下是一个示例:


-2
投票
在您的示例中,将find的输出传递给xargs的一点是,find的-exec选项的标准行为是对每个找到的文件执行一次命令。如果您使用的是find,并且想要它的标准行为,那么答案很简单-请勿使用xargs开头。

-3
投票
在当前或子文件夹中的每个build.xml上执行ant任务全清理。

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


178
投票

在我看来,此页面上所有现有的答案都是错误的,包括标记为正确的答案。这是因为问题的措词含糊。

摘要:如果要执行命令“对于给定的每一行输入仅执行一次,”将整个行(不带换行符)作为单个参数,]传递给命令>那么这是最佳的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精确执行一次命令?它的默认行为是对输入到参数

进行分块并执行尽可能少的次数,将多个arguments传递给每个实例。那么答案是-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准确地执行命令with

一个参数?它的默认行为是对行around whitespace进行分块。那么答案就更微妙了。

[有人认为-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"

如果您要为来自find

每条

行(即结果)运行命令,那么您需要xargs用于什么?
尝试:

find

路径

-type f -exec您的命令 {} \;[文字{}被文件名替换,\;需要文字find才能知道自定义命令在此结束。

编辑:

(在修改您的问题以澄清您对-exec的了解之后]

来自man xargs

-L

最大行数每个命令行最多使用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

如何使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将换行符转换为空(\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 

before

的输出,将中断转换为null。
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 path -type f | xargs -L1 command
这就是您所需要的。

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

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

示例用例:

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

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

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

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

使用xargs(GNU findutils)4.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.
[我似乎没有足够的声誉在Tobia's answer above上添加评论,所以我添加此“答案”来帮助希望在Windows平台上以相同方式尝试xargs的我们这些人。

这里是Windows批处理文件,与Tobia快速编码的“显示”脚本具有相同的作用:

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

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

我正在尝试xargs命令,但发现“ -0”与“ -L”完美配合。即使空格也被处理(如果输入为null终止)。以下是一个示例:

#touch "file with space" #touch "file1" #touch "file2"

以下内容将拆分空值,并对列表中的每个参数执行命令:

#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”才能正常工作。 

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

在当前或子文件夹中的每个build.xml上执行ant任务全清理。

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


22
投票
如果您要为来自find

每条


16
投票
如何使xargs对给定的每一行输入执行一次命令?

10
投票
另一个替代方法...

4
投票
find path -type f | xargs -L1 command

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

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

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


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.
© www.soinside.com 2019 - 2024. All rights reserved.