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

我怎么能让xargs执行命令准确地为每一行输入给定? 它的默认行为是将行分块并执行一次命令,将多行传递给每个实例。< / p >

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

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

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

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

我知道那个发现有"执行"的标志。我只是从另一种资源中引用了一个说明性的例子。

270412 次浏览

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

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或——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的目的是,find的-exec选项的标准行为是对每个找到的文件执行一次命令。如果您正在使用find,并且想要它的标准行为,那么答案很简单——一开始就不要使用xargs。

如果你想为来自find每一个行(即result)运行命令,那么你需要xargs做什么?

试一试:

__abc0 __abc3 __abc1 __abc4 __abc2

其中字面量{}被文件名代替,而字面量\;find所需要的,以便知道自定义命令在那里结束。

编辑:

(在编辑你的问题,澄清你知道-exec之后)

man xargs:

< p > - l max-lines < br > 每个命令行最多使用max-lines非空输入行。落后于 空格使一个输入行在逻辑上被下一个输入行继续。 意味着- x。< / p >

注意,如果你使用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
find path -type f | xargs -L1 command

这就是你所需要的。

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

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

用xargs (GNU findutils) 4.4.0测试

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

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

另一种选择……

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文件包含空格。

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

简介:如果你想要执行命令对于每一行输入,“;,将整行(不带换行符)作为单一参数,传递给命令,那么这是最好的unix兼容方式:

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

如果你正在使用GNU xargs并且不需要与所有其他UNIX兼容(FreeBSD, Mac OS X等),那么你可以使用特定于GNU的选项-d:

... | xargs -d\\n -n1 ...

现在来解释一下…


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

  1. 它如何将输入分割成“;参数”;;而且
  2. 一次传递子命令多少个参数。

为了测试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"

如果最初的问题是关于第二点的。上面(我认为是这样,读了几遍之后),它是这样读的(粗体的变化):

我怎么能让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"

另一方面,如果最初的问题是关于第一点的。输入分割,它是这样读的(许多人似乎认为是这样的情况,或者混淆了这两个问题):

我怎么能让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"

如上所述,如果你正在使用GNU xargs,你可以用特定于GNU的选项-d替换tr:

$ echo $'one \ntwo\nthree and four' | xargs -d\\n -n1 ./show
-> "one "
-> "two"
-> "three and four"

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

-L 1是一个简单的解决方案,但如果任何文件中包含空格,它就不起作用。这是find -print0实参的一个关键函数——用'\0'字符而不是空格分隔实参。这里有一个例子:

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 之前的输出,将换行符转换为null。

find . -name \*.xml | grep -v /target/ | tr '\n' '\0' | xargs -0 tar -cf xml.tar

似乎我没有足够的声誉给上面是托比亚的回答添加注释,所以我添加这个“答案”来帮助那些想在Windows平台上以同样的方式实验xargs的人。

下面是一个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.

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

我正在尝试xargs命令,我发现“-0”与“-L”完美地工作。即使空格也会被处理(如果输入以空结尾)。举例如下:

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

下面的代码将拆分null值,并对列表中的每个参数执行命令:

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

所以-L1将对每个以空结尾的字符执行参数,如果与"-0"一起使用。要看区别,试试:

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