xargs 擅长插入初始参数:
seq 0 10 | xargs -n 3 echo foo
产生以下输出:
foo 0 1 2
foo 3 4 5
foo 6 7 8
foo 9 10
当我也想要尾随参数时怎么办? 也就是什么命令:
seq 0 10 | xargs -n 3 <WHAT GOES HERE?>
将产生以下所需的输出:
foo 0 1 2 bar
foo 3 4 5 bar
foo 6 7 8 bar
foo 9 10 bar
我尝试了以下方法:
seq 0 10 | xargs -n 3 -I {} echo foo {} bar
这几乎是正确的,除了它显然强制每个命令行 1 个项目,这不是我想要的:
foo 0 bar
foo 1 bar
foo 2 bar
foo 3 bar
foo 4 bar
foo 5 bar
foo 6 bar
foo 7 bar
foo 8 bar
foo 9 bar
foo 10 bar
在从 @netniV 的答案中抢先弄清楚这一点之后, 我现在看到手册页实际上包含一个示例 展示如何做:
xargs sh -c 'emacs "$@" < /dev/tty' emacs
启动所需的最小数量的 Emacs 副本,在 其他,编辑 xargs 标准输入上列出的文件。这个例子 达到与 BSD 的 -o 选项相同的效果,但以更灵活和可移植的方式。
并且wikipedia页面显示了类似的技术,最后对虚拟参数进行了解释:
实现类似效果的另一种方法是使用 shell 作为启动命令,并处理该 shell 中的复杂性,例如 示例:
$ mkdir ~/backups $ find /path -type f -name '*~' -print0 | xargs -0 bash -c 'for filename; do cp -a "$filename" ~/backups; done' bash
行尾的单词
被bash
解释为特殊参数bash -c
。如果 bash 这个词不存在,则名称 第一个匹配的文件将被分配给$0
并且该文件不会 复制到$0
。可以使用任何单词代替~/backups
,但是 因为bash
通常会扩展为 shell 或 shell 脚本的名称 被执行,$0
是一个不错的选择。bash
所以,具体做法如下:
seq 0 10 | xargs -n 3 sh -c 'echo foo "$@" bar' some_dummy_string
输出如预期:
foo 0 1 2 bar
foo 3 4 5 bar
foo 6 7 8 bar
foo 9 10 bar
使用xargs的-i参数如:
ls -1 | xargs -t -i echo "Found {} file"
请注意,-t 仅用于显示将发出的命令。实时运行时,请省略 -t 参数。
{}
被实际参数替换。请注意,这确实意味着每个命令每个文件仅运行一次。不是作为一组文件。如果需要使用不同的替换字符串,请在 -i 之后指定
ls -1 | xargs -t -i[] xargs echo "Found []{} file"
将在文件名后保留
{}
,现在在出现 []
时被替换
创建一个名为 runme.sh 的脚本文件
#!/bin/sh
echo "foo $@ bar"
确保 chmod +X 然后使用
seq 0 10 | xargs -n 3 ./runme.sh
这会产生
foo tests tree.php user_admin.php bar
foo user_domains.php user_group_admin.php utilities.php bar
foo vdef.php bar
我发现将对
xargs
的调用分成两部分要容易得多,就像这样
seq 0 10 | xargs -n 3 | xargs -I {} echo foo {} bar
第一个有一个隐式的
echo
命令,所以输出将是
0 1 2
3 4 5
6 7 8
9 10
而在第二个中,
-I
有一个隐式的-L1
,一次选择一行,给出所需的输出
foo 0 1 2 bar
foo 3 4 5 bar
foo 6 7 8 bar
foo 9 10 bar