xargs
在shell脚本中被广泛使用;通常可以使用while read -r; do ... done
或while read -ar; do ... done
循环在bash中重新构造这些用法。
何时应该优先考虑使用xargs
,何时应该优先考虑使用while-read循环?
while
循环的问题在于它们倾向于逐个处理项目,有时是不必要的。这就是xargs
的优点所在 - 它可以批量处理参数,让一个命令处理大量项目。例如,一个while循环:
pax> echo '1
2
3
4
5' | while read -r; do echo $REPLY; done
1
2
3
4
5
以及相应的 xargs
:
pax> echo '1
2
3
4
5' | xargs echo
1 2 3 4 5
你可以看到,这里通过使用while
和xargs
分别逐行和一次性处理所有行。换句话说,前者相当于echo 1 ; echo 2 ; echo 3 ; echo 4 ; echo 5
,而后者相当于echo 1 2 3 4 5
(五个进程与一个进程相比)。在处理数千或数万行时,这真的会有很大的区别,因为创建进程需要时间。
当使用能够接受多个参数的命令时,大多数情况下都是有利的,因为它减少了启动单个进程的数量,使得事情更快速。
当我处理小文件或要运行的命令对每个项目都很复杂(我懒得编写单独的脚本给xargs
),我会使用while
变体。
当我关注性能(大文件)时,即使我必须编写单独的脚本,我也会使用xargs
。
一些xargs
的实现还可以理解一个-P MAX-PROCS
参数,它允许xargs
并行运行多个作业。使用while read
循环模拟这种情况会相当困难。
GNU Parallel http://www.gnu.org/software/parallel/具有xargs
(使用-m)的优点和以换行符作为分隔符的while-read
的优点,还有一些新功能(例如输出分组,远程计算机上作业的并行运行和上下文替换)。
如果您安装了GNU Parallel,则我看不到您会使用xargs
的任何情况。而我只会在执行块太大而无法放在单行中时(例如,如果它包含if语句或类似内容),并且您拒绝创建bash函数的情况下使用read-while
。
对于所有小型脚本,我实际上发现使用GNU Parallel更易读。paxdiablo的示例:
echo '1
2
3
4
5' | parallel -m echo
使用GNU Parallel将WAV文件转换为MP3:
find sounddir -type f -name '*.wav' | parallel -j+0 lame {} -o {.}.mp3
观看GNU Parallel的介绍视频:http://www.youtube.com/watch?v=OpaiGYxkSuQ
xargs"有一个选项“-n max-args”,我猜想这将允许一次性为多个参数调用命令(对于“grep”、“rm”和许多其他类似程序非常有用)。 尝试从手册页面中获取示例:
"cut -d: -f1 < /etc/passwd | sort | xargs -n 5 echo
你会看到它每行“回显”了5个用户
P.S. 别忘了,“xargs”是一个程序(就像子shell)。因此,没有简单的方法将信息传递给你的shell脚本(你需要读取“xargs”的输出并以某种方式解释来填充你的shell/env变量)。
find
或 pkgutil
等。要使用 xargs
,你需要首先使用 sed
将行用引号括起来,但这看起来很笨重。find
之外的其他地方获取文件列表...function process {
while read line; do
test -d "$line" && echo "$line"
done
}
find . -name "*foo*" | process
find
命令的输出,你可以使用它的-exec
选项或者使用空字符代替换行符,使用find <something> -print0 | xargs -0 …
命令。这种方法的优点是可以正确处理文件名中的换行符。 - Arch Stanton
xargs
的优点是独立于所使用的 shell,而我从来不确定在一个 shell 中有效的语法是否在另一个 shell 中同样有效。 - bers