gpt4 book ai didi

bash - 在 bash 中,使用进程替换或管道通常更好吗

转载 作者:行者123 更新时间:2023-11-29 09:05:49 29 4
gpt4 key购买 nike

在单个命令的输出仅被另一个命令使用的用例中,使用 | 是否更好? ( pipelines ) 或 <() ( process substitution )?

当然,更好是主观的。对于我的特定用例,我追求性能作为主要驱动因素,但也对稳健性感兴趣。

while read do done < <(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。

如果你设置shopt -s lastpipe在 bash 4.2+ 中,bash 模仿 kshzsh行为和工作正常。

2。 Bash 不会等待进程替换完成。

POSIX 只需要一个 shell 来等待管道中的最后一个进程,但大多数 shell 包括 bash将等待所有这些。

当你有一个缓慢的生产者时,这会产生显着差异,比如在 /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?

第一个示例的基准测试结果不佳。一次head满意并退出,tr将等待下一个write()打电话才发现水管坏了。

因为 bash 等待两个 headtr完成,它会显得更慢。

在 procsub 版本中,bash 只等待 head ,并让 tr在后台完成。

3。 Bash 目前没有为进程替换中的单个简单命令优化 fork 。

如果您调用外部命令,如 sleep 1 ,然后 Unix 进程模型要求 bash fork 并执行命令。

由于 fork 很昂贵,bash 优化了它可以优化的情况。例如命令:

bash -c 'sleep 1'

会天真地产生两个分支:一个运行 bash,一个运行 sleep .但是,bash 可以优化它,因为不需要 bash。在sleep之后留下来完成,所以它可以代替自己替换为 sleep ( execve 没有 fork )。这与尾调用优化非常相似。

( sleep 1 )同样进行了优化,但是 <( sleep 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

鉴于上述情况,您可以创建一个有利于您想要的任何位置的基准,但由于 fork 的数量通常更为相关,因此管道将是最好的默认设置。

显然,管道是 POSIX 标准,是连接两个进程的标准输入/标准输出的规范方式,并且在所有平台上都同样有效,这并没有什么坏处。

关于bash - 在 bash 中,使用进程替换或管道通常更好吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48485029/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com