在bash中,通常使用流程替换或管道更好
在使用单个命令的输出仅被另一个消耗的用例中,使用|更好(
pipelines)或<()(
process substitution)?
当然,更好是主观的.对于我的具体用例,我是以性能为主要驱动因素,但也对稳健性感兴趣. while read read do< <(cmd)我已经知道并已切换到的好处. 我有几个var = $(cmd1 | cmd2)个实例我怀疑可能更好地替换为var = $(cmd2<<(cmd1)). 我想知道后一种情况对前者带来哪些具体好处.
tl; dr:使用烟斗,除非你有令人信服的理由不这样做.
从进程替换中管道和重定向stdin基本上是相同的:两者都将导致由匿名管道连接的两个进程. 有三个实际差异: 1. Bash默认为管道中的每个阶段创建一个分支. 这就是为什么你首先开始研究这个问题: #!/bin/bash cat "$1" | while IFS= read -r last; do true; done echo "Last line of $1 is $last" 默认情况下,此脚本不会使用管道,因为与ksh和zsh不同,bash将为每个阶段分叉子shell. 如果你在bash 4.2中设置shopt -s lastpipe,bash会模仿ksh和zsh行为并且工作得很好. 2. Bash不等待进程替换完成. POSIX只需要一个shell来等待管道中的最后一个进程,但是包括bash在内的大多数shell都会等待所有这些进程. 当你有一个慢生产者时,这会产生一个显着的差异,就像在/ dev / random密码生成器中一样: tr -cd 'a-zA-Z0-9' < /dev/random | head -c 10 # Slow? head -c 10 < <(tr -cd 'a-zA-Z0-9' < /dev/random) # Fast? 第一个例子不会有利地进行基准测试.一旦头部满足并退出,tr将等待其下一次write()调用以发现管道损坏. 由于bash等待head和tr完成,它看起来似乎更慢. 在procsub版本中,bash只等待head,并让tr在后台完成. 3. Bash目前没有针对流程替换中的单个简单命令优化离开. 如果调用sleep 1之类的外部命令,那么Unix进程模型需要bash forks并执行命令. 由于叉子价格昂贵,bash优化了它可以的情况.例如,命令: bash -c 'sleep 1' 天真地会产生两个叉子:一个用于运行bash,一个用于运行睡眠.但是,bash可以对它进行优化,因为在完成睡眠后不需要使用bash来保持它,所以它可以用sleep替换它自己(execve没有fork).这与尾调用优化非常相似. (睡眠1)被类似地优化,但是<(睡眠1)不是. source code没有提供特殊原因,所以它可能没有出现. $strace -f bash -c '/bin/true | /bin/true' 2>&1 | grep -c clone 2 $strace -f bash -c '/bin/true < <(/bin/true)' 2>&1 | grep -c clone 3 鉴于上述情况,您可以创建一个支持您想要的任何位置的基准,但由于叉的数量通常更相关,因此管道将是最佳默认值. 显然,管道是POSIX标准,连接两个进程的stdin / stdout的规范方式,并且在所有平台上同样运行良好,这并没有什么坏处. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |