xargs命令总是让我感到困惑。

请考虑以下两个示例:对touch的命令将需要xargs

$ \ls | grep Cases | less


#1 楼

不同之处在于目标程序接受的数据是什么。一次排队。但是,某些程序不接受标准输入的命令,他们希望在命令的参数中将其拼写清楚。例如,touch在命令行上将文件名作为参数,如下所示:touch file1.txt

如果您有一个程序在标准输出上输出文件名,并希望将它们用作touch的参数,使用xargs来读取STDIN流数据,并将每行转换为该命令的以空格分隔的参数。

这两项是等效的: />除非您确切知道它在做什么以及为什么需要它,否则不要使用xargs。通常情况下,有一种比使用xargs强制转换更好的方法来完成这项工作。转换过程还充满了潜在的陷阱,例如转义和单词扩展等。

评论


该警告对我来说有点难受。在将流发送到命令行的两个常见选项(xargs和$(...))中,xargs比命令替换安全得多。而且我不记得曾经遇到过带有换行符的合法文件名。命令替换而不是xargs的转义和单词扩展陷阱不是问题吗?

– camh
2011年11月19日在22:31

@camh:两者都是潜在的陷阱。在外壳程序中,您必须担心文件名在空格,制表符和换行符之间会分开。在xargs中,您只需要担心换行符。在xargs中,如果输出格式正确,则可以改为在NUL字符上分割单词/文件名(xargs -0),这与find -print0结合使用非常有用。

–肯·布鲁姆
2011年11月20日在1:22

xargs是通过带有空格的args通过外壳调用程序,还是实际上在内部构造参数列表(例如,用于execv / execp)?

–甜蜜地
2011年11月20日9:55



它在内部构造它并使用execvp,因此很安全。同样,尽管BSD xargs(OSX等)似乎不支持此选项,但GNU xargs(在Linux和其他一些Linux上使用)使您可以将换行符指定为-d \ n。

–蓬松
2011年11月21日,0:20



#2 楼

为了扩展已经提供的答案,xargs可以做一件很酷的事情,在当今的多核和分布式计算领域中,它变得越来越重要:它可以并行处理作业。

例如:

$ find . -type f -name '*.wav' -print0 |xargs -0 -P 3 -n 1 flac -V8


将一次使用三个进程(-P 3)对* .wav => * .flac进行编码。

评论


哇。我应该在一周前用50GiB的WAV做完全相同的事情(使用OGG除外)时知道这一点。 :)

–阿洛瓦·马哈德(Alois Mahdal)
2012年5月13日在21:38

为什么不使用find具有的-exec参数?

–Evgeny
2012年9月11日上午9:46

@Evgeny -exec参数不会并行处理作业。

–amphetamachine
2012-09-18 12:56

需要注意的是,xargs的-0参数使其将NULL字符视为输入项定界符。查找-print0输出以NULL分隔的项目。对于可能包含空格,引号或其他特殊字符的文件名,这是一个好习惯。

– Dan Dascalescu
19年1月6日在9:02

#3 楼

当您在stdin上具有文件路径列表并且想要对它们进行某些操作时,xargs特别有用。例如:

$ git ls-files "*.tex" | xargs -n 1 sed -i "s/color/colour/g"


让我们一步一步地检查一下:

$ git ls-files "*.tex"
tex/ch1/intro.tex
tex/ch1/motivation.tex
....


换句话说,我们的输入是我们要执行的路径的列表。

要找出xargs对这些路径有何作用,一个不错的技巧是在命令前添加echo,如下所示:

$ git ls-files "*.tex" | xargs -n 1 echo sed -i "s/color/colour/g"
sed -i "s/color/colour/g" tex/ch1/intro.tex
sed -i "s/color/colour/g" tex/ch1/motivation.tex
....


-n 1参数将使xargs将每一行变成自己的命令。对于指定的文件,sed -i "s/color/colour/g"命令会将所有出现的color替换为colour。如果这样做,则应通过传递-0标志,将空终止路径用作xargs的输入。一个示例用法是:

$ git ls-files -z "*.tex" | xargs -0 -n 1 sed -i "s/color/colour/g"


与我们上面描述的操作相同,但是如果其中一个路径中有空格,也可以使用。 >
这适用于任何将文件名作为输出生成的命令,例如findlocate。如果确实在带有大量文件的git存储库中使用它,则将它与git grep -l而不是git ls-files一起使用可能会更高效,例如:

$ git grep -l "color" "*.tex" | xargs -n 1 sed -i "s/color/colour/g"


git grep -l "color" "*.tex"命令将给出包含短语“ color”的“ * .tex”文件列表。

评论


没错,但是,如果您已了解到这一点,则还应该了解为什么循环遍历find的输出错误做法?

–通配符
16年11月16日下午5:32

#4 楼

您的第一个参数很好地说明了区别。

\ls | grep Cases | less使您可以浏览lsgrep生成的文件名列表。它们恰好是文件名并不重要,它们只是一些文本。 \ls | grep Cases | xargs less将文件名列表作为输入并在其命令行上输入命令,并在其命令行上运行带有文件名的命令。

当考虑使用xargs时,请记住它期望输入以奇怪的方式格式化:用空格分隔,用xargs\'进行引号(以一种不寻常的方式,因为"在引号内不是特殊的)。如果您的文件名不包含空格或\,请仅使用xargs

评论


@Gilles:xargs具有-0,--null选项来解决空格问题(很可能是我从您那里学到的:),所以我假设您是指无选项xarg调用,但是您对引用的引用感到困惑。您是否有链接或相关示例? ..(ps。| xargs less是一个方便的“把戏” +1 ..谢谢..

– Peter.O
2011年12月1日于20:59

#5 楼

在您的示例中,您根本不需要使用xargs,因为find可以准确而安全地执行您想做的事情。
find -maxdepth 1 -name '*Cases*' -exec touch {} +


在此示例中,find表示仅在当前目录中搜索,而不会进入任何子目录;默认情况下,除非使用maxdepth约束查找,否则find将查找所有子目录(通常是您想要的)。 -maxdepth 1是将被替换的文件名,而{}是两个命令结束标记之一,另一个是+。它们之间的区别在于,;意味着一次在每个文件上执行该命令,而;意味着一次在所有文件上执行该命令。但是请注意,您的外壳可能会尝试解释+本身,因此您需要使用;\;对其进行转义。是的,';'有点像这样的烦恼,但是它的功能远远不能弥补。为了帮助您学习find,请尝试使用findxargs选项,它们将向您显示即将执行的命令并提示您是否要运行它。代替xargs来提示您是否要运行该命令。 。-p命令将仅接受出现的--interactive的一个实例,因此,如果您遇到find的错误,那么您可以这样做:-ok

您可以在GNU中了解有关运行命令的更多信息Findutils手册。

另外,我提到-exec可以安全地执行您想要的操作,因为当您处理文件时,除非使用findxargs选项以及会生成以结尾的输入项的东西,否则您将遇到空格和其他会引起-exec问题的字符空字符而不是空格。

评论


对,就是这样。为什么遍历find的输出是不好的做法?

–通配符
16年11月16日下午5:33

@Wildcard文件名带有空格或字符,例如'或'可能会出现问题,而find可以毫无问题地处理这些情况。

– aculich
16 Dec 4'在18:33

是的我知道。请参阅我对链接问题的回答。我可能应该在上述评论的声明中改写该问题,或者在其前面添加“查看问题...”。 :D

–通配符
16年4月4日在21:23

#6 楼

xargs(以及findsortduuniqperl等)接受命令行开关,说“ STDIN具有文件列表,以NUL(0x00)字节分隔”。这使得处理带有空格和其他有趣字符的文件名变得容易。文件名不包含NUL。

评论


我认为您的意思是“文件名不能包含空值”。

–amphetamachine
2011-11-23 5:50