为什么应该避免在Bash脚本中使用管道?

3
大多数情况下,当我看到有人在Bash脚本中建议使用管道时,总会有人指出不要使用它,而是仅使用一个命令。
例如:
find $dir -name $pattern

替代

ls $dir | grep $pattern

除了外观,还有其他原因避免使用管道吗?


1
不应解析 ls 的输出:http://mywiki.wooledge.org/ParsingLs - ymonad
你知道这两个命令之间的区别吗?find 命令还会搜索子目录,而 ls 命令则不会。 - fancyPants
@fancyPants 是的,我指的确切命令应该是 "ls $dir | grep -i $pattern" 和 "find $dir -maxdepth 1 -iname '$patter' -exec basename {} .po ;"。使用这些命令您应该能够得到相同的输出,但是 find 命令似乎更加复杂。但问题更多关于管道操作。 - realape
2个回答

3

管道本身并没有问题。应该避免的是无用的fork(),这意味着启动一个进程是一件相对耗时的事情。

如果某个操作可以在一个进程中完成,通常比使用两个进程获得相同的结果更好。


我认为所需的 execfork 更昂贵。有人有数据吗? - W.Mann
你可以轻松测试它,但fork()涉及创建一个新进程,复制当前进程,使用锁定等,而execl只是替换当前进程。 - marcolz
复制当前进程?你必须复制上下文,但不是内存本身。至少在Linux中,“fork”是基于写时复制实现的。 - W.Mann
@W.Mann 是的,你在可写页面上的写时复制是正确的。然而链接到它们的页表必须被复制,以及所有打开的文件描述符等。 - marcolz

2

因为管道会创建一个新的进程。在你的例子中,ls和grep是两个进程,find是一个进程。一个或多个管道会使命令变慢。以下是一个简单的例子:

$ time find Downloads -name *.pdf &>/dev/null

real    0m0.019s
user    0m0.012s
sys 0m0.004s

$ time ls Downloads | grep pdf &>/dev/null

real    0m0.021s
user    0m0.012s
sys 0m0.004s

原则上是正确的,但也有不同的语义。ls还按字母顺序对输出进行排序,而find仅使用底层系统命令返回的顺序。此外,正如已经指出的那样,find是递归的。 - W.Mann
你只是在计时ls命令,而不是grep命令。 - marcolz
@W. Mann:没错,在 bashtime 内建命令中,就是这个情况。 - marcolz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接