什么时候应该优先选择xargs而不是while-read循环?

时间:2010-04-04 10:20:59

标签: linux bash xargs

xargs广泛用于shell脚本;使用while read -r; do ... donewhile read -ar; do ... done循环通常很容易在bash中重新构建这些用法。

何时应首选xargs,何时首选while-read循环?

6 个答案:

答案 0 :(得分:25)

具有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),我将使用{{1}变种。

我对性能(大文件)感兴趣,即使我必须编写单独的脚本,我也会使用while

答案 1 :(得分:5)

“xargs”有选项“-n max-args”,我想这将允许一次调用几个参数的命令(对“grep”,“rm”以及更多此类程序有用) 试试man-page的例子:

cut -d: -f1 < /etc/passwd | sort | xargs -n 5 echo

你会看到它“回应” - 每行5个用户

P.S。并且不要忘记“xargs” - 是程序(如子shell)。因此无法以简单的方式获取shell脚本的信息(您需要读取“xargs”的输出并以某种方式解释以填充shell / env变量)。

答案 2 :(得分:5)

xargs的某些实现也理解-P MAX-PROCS参数,它允许xargs并行运行多个作业。使用while read循环进行模拟非常困难。

答案 3 :(得分:5)

GNU Parallel http://www.gnu.org/software/parallel/具有xargs(使用-m)和while-read的优点,其中newline作为分隔符和一些新功能(例如输出分组,并行运行远程计算机上的作业和上下文替换。)

如果您安装了GNU Parallel,我看不到您使用xargs的情况。并且我将使用read-while的唯一情况是,如果要执行的块太大,则放入一行(例如,如果它包含if语句或类似内容)变得不可读并且您拒绝创建bash功能。

对于所有小脚本,我实际上发现它使用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

答案 4 :(得分:2)

相反,有些情况下你有一个文件列表,每行1个,包含空格。例如。来自findpkgutil或类似的。要使用xargs,您必须首先使用sed用引号括起来,但这看起来很笨拙。

使用while循环,脚本可能看起来更容易读/写。引用受空间污染的args是微不足道的。下面的示例是人为的,但想象一下从find ...

以外的其他内容获取文件列表
function process {
  while read line; do
    test -d "$line" && echo "$line"
  done
}

find . -name "*foo*" | process

答案 5 :(得分:1)

我不明白,人们一直在讨论如何在循环中而不是在循环之外执行。我对linux的方面知之甚少,但我知道使用MS-DOS的变量构建参数列表相当简单,或者&gt; file,cmd&lt;如果超出行长度限制,则建立参数列表。

或者有人说linux不像ms-dos那么好吗? (天啊,我知道你可以构建链,因为许多bash脚本显然正在这样做,而不是在循环中)。

此时,它成为内核限制/偏好的问题。 xargs并不神奇;管道确实比字符串构建有好处(好吧,ms-dos;你可以用#34;指针和#34构建字符串;并且避免任何复制(毕竟它是虚拟内存,除非你要更改数据)你可以跳过字符串concat中的费用...但管道是一个更原生的支持))。实际上,我不认为我可以给它带来并行处理的优势,因为你可以轻松地创建几个任务循环来查看切片数据(如果你避免复制,这也是一个非常快速的动作)。

最后,xargs更多用于内联命令,速度优势可以忽略不计(编译/解释字符串构建之间的差异)因为它所做的一切,你可以通过shell脚本来完成。