这个xargs
命令总是让我感到困惑。有一般规则吗?
请考虑以下两个例子:
$ \ls | grep Cases | less
打印与“Cases”匹配的文件,但将命令更改为touch
将需要xargs
:
$ \ls | grep Cases | touch
touch: missing file operand
Try `touch --help' for more information.
$ \ls | grep Cases | xargs touch
答案1
不同之处在于目标程序接受的数据。
如果您只使用管道,它会接收 STDIN(标准输入流)上的数据作为一堆原始数据,并且一次可以对一行进行排序。然而,有些程序不接受标准输入的命令,它们希望在命令的参数中拼写出来。例如,touch
在命令行上将文件名作为参数,如下所示:touch file1.txt
.
如果您有一个输出文件名的程序标准输出并想使用它们作为参数到touch
,您必须使用xargs
它读取 STDIN 流数据并将每一行转换为命令的空格分隔的参数。
这两件事是等价的:
# touch file1.txt
# echo file1.txt | xargs touch
xargs
除非您确切知道它在做什么以及为什么需要它,否则不要使用。通常情况下,有比使用xargs
强制转换更好的方法来完成这项工作。转换过程也充满了潜在的陷阱,如转义和单词扩展等。
答案2
为了扩展已经提供的答案,xargs
可以做一件很酷的事情,这在当今的多核和分布式计算领域变得越来越重要:它可以并行处理作业。
例如:
$ find . -type f -name '*.wav' -print0 |xargs -0 -P 3 -n 1 flac -V8
将同时使用三个进程对 *.wav => *.flac 进行编码 ( -P 3
)。
答案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
请注意,这仅在路径中没有任何空格的情况下才有效。如果这样做,您应该通过传递标志来使用以 null 结尾的路径作为 xargs 的输入-0
。一个示例用法是:
$ 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”文件列表。
答案4
xargs
在您的示例中,您根本不需要使用,因为find
它将准确且安全地执行您想要执行的操作。
您想要使用的正是find
:
find -maxdepth 1 -name '*Cases*' -exec touch {} +
在这个例子中-maxdepth 1
意味着只在当前目录中搜索,不深入到任何子目录;默认情况下,find 将查找所有子目录(这通常是您想要的),除非您使用 maxdepth 对其进行约束。是{}
将在其位置替换的文件的名称,是+
两个命令结束标记之一,另一个是;
.它们之间的区别在于,;
意味着一次对每个文件执行该命令,而+
意味着一次对所有文件执行该命令。但请注意,您的 shell 可能会尝试解释;
自身,因此您需要使用 或 对其进行\;
转义';'
。是的,find
有很多这样的小烦恼,但它的力量足以弥补它。
两者一开始学习起来都很棘手find
。xargs
为了帮助您学习,xargs
请尝试使用-p
或--interactive
选项,该选项将显示它将要执行的命令并提示您是否要运行它。
类似地,find
您可以使用-ok
代替 来-exec
提示您是否要运行该命令。
不过,有时候,您find
无法完成您想做的所有事情,这就是xargs
出现的地方。该-exec
命令只接受{}
出现的一个实例,因此,如果您在使用 so 时出现错误,find -type f -exec cp {} {}.bak \;
您可以这样做:find -type f -print0 | xargs -0 -l1 -IX cp X X.bak
您可以了解更多有关运行命令在里面GNU Findutils 手册。
另外,我提到可以find
安全地执行您想要的操作,因为当您处理文件时,您将遇到空格和其他字符,这将导致问题,xargs
除非您使用-0
or--null
选项以及生成以空字符终止的输入项的内容的空白。