Answers:
不同之处在于目标程序接受什么数据。
如果仅使用管道,它将接收STDIN(标准输入流)上的数据,作为原始数据堆,它可以一次通过一行进行排序。但是,某些程序不接受标准输入的命令,他们希望在命令的参数中将其拼写清楚。例如touch
,在命令行上将文件名作为参数,如下所示:touch file1.txt
。
如果你有一个程序,输出文件名的标准输出和要使用它们作为参数来touch
,你必须使用xargs
它读取STDIN流数据每行转换为空格分隔参数的命令。
这两件事是等效的:
# touch file1.txt
# echo file1.txt | xargs touch
xargs
除非您确切知道它在做什么以及为什么需要它,否则不要使用。通常情况下,有一种比xargs
强制转换更好的方法来完成这项工作。转换过程还充满了潜在的陷阱,例如转义和单词扩展等。
xargs -0
),这与结合使用非常有用find -print0
。
xargs
通过与空格分隔ARGS外壳调用程序,或者它实际上构造参数列表内部(如与使用execv
/ execp
)?
-d \n
尽管BSD xargs(OSX等)似乎不支持此选项,但是GNU xargs(在Linux和其他一些Linux上使用)使您可以指定换行符作为分隔符。
要扩展已经提供的答案,xargs
可以做一件很酷的事情,在当今的多核和分布式计算领域中,它变得越来越重要:它可以并行处理作业。
例如:
$ find . -type f -name '*.wav' -print0 |xargs -0 -P 3 -n 1 flac -V8
将一次使用三个过程(-P 3
)对* .wav => * .flac进行编码。
-exec
参数不会并行处理作业。
当您在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"
它与我们上面描述的相同,但是如果其中一条路径中有空格,也可以使用。
这适用于将文件名作为输出生成的任何命令,例如find
或locate
。如果您确实在带有大量文件的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”文件列表。
您的第一个论点很好地说明了差异。
\ls | grep Cases | less
使您可以浏览ls
和生成的文件名列表grep
。它们恰好是文件名,这只是文本而已。
\ls | grep Cases | xargs less
使您可以浏览名称由命令第一部分产生的文件。xargs
将文件名列表作为输入并在其命令行上输入命令,并在其命令行上运行带有文件名的命令。
当使用考虑xargs
,请记住,它预计在输入一种奇怪的方式格式化:空格分隔,用\
,'
以及"
用于引用(在一个不寻常的方式,因为\
没有特殊的引号内)。仅xargs
当您的文件名不包含空格或时使用\'"
。
xargs
可以-0, --null
选择解决空格问题(很可能是我从您那里了解到的:),所以我假设您是指无选项xarg
调用,但是您对引号的引用感到困惑。您是否有链接或相关示例?..(PS | xargs less
是一个方便的“绝招” +1 ..感谢..
在您的示例中,您根本不需要使用xargs
任何东西,因为find
它将完全安全地完成您想做的事情。
您要使用的find
正是:
find -maxdepth 1 -name '*Cases*' -exec touch {} +
在此示例中,-maxdepth 1
意味着仅在当前目录中进行搜索,而不会进入任何子目录;默认情况下,除非使用maxdepth约束查找,否则find将查找所有子目录(通常是您想要的)。的{}
是,将获得取代它的位置和文件名+
是两个结束命令标志之一,另一个是;
。它们之间的区别在于,这;
意味着一次在每个文件上执行该命令,而+
意味着一次对所有文件执行该命令。但是请注意,您的外壳可能会尝试解释;
自身,因此您需要使用\;
或对其进行转义';'
。是的,find
有很多类似的小烦恼,但它的力量足以弥补这一不足。
两者find
和一开始xargs
都很难学习。为了帮助您学习,请xargs
尝试使用-p
或--interactive
选项,该选项将向您显示即将执行的命令,并提示您是否要运行该命令。
同样,find
您可以使用-ok
代替-exec
提示您是否要运行该命令。
但是,有时有时find
无法执行所需的所有操作,而这正是其中的xargs
来源。该-exec
命令将仅接受{}
出现的一个实例,因此,如果您遇到错误,find -type f -exec cp {} {}.bak \;
则可以这样做:find -type f -print0 | xargs -0 -l1 -IX cp X X.bak
您可以在GNU Findutils手册中了解有关运行命令的更多信息。
另外,我提到可以find
安全地执行您想要的操作,因为当您处理文件时,xargs
除非使用-0
或--null
选项以及生成以空字符终止的输入项的东西,否则您将遇到空格和其他会引起问题的字符空格。
'
或)"
可能会出现问题,而find
可以毫无问题地处理这些情况。
xargs
(沿find
,sort
,du
,uniq
,perl
和其他几个人)接受命令行开关说“STDIN有文件的列表,由NUL(0×00)字节分开”。这使得处理带有空格和其他有趣字符的文件名变得容易。文件名不包含NUL。
xargs
和$(...)
),xargs的远比命令替换更安全。而且我不记得曾经遇到过带有换行符的合法文件名。命令替换而不是xargs的转义和单词扩展陷阱不是问题吗?