gpt4 book ai didi

bash - 为什么我的 bash 脚本会阻塞?

转载 作者:行者123 更新时间:2023-11-29 08:57:45 26 4
gpt4 key购买 nike

我有一个 bash 脚本:my.sh

#!/bin/bash

do_sth()
{
sleep 5
}

main()
{
do_sth >/dev/null &
echo do sth in background ...
}

if [ "$1" = "1st_way" ]; then
main
elif [ "$1" = "2nd_way" ]; then
main >/dev/null
fi

下面的命令立即返回

./my.sh 1st_way | cat

但是,下面的命令会阻塞 5 秒

./my.sh 2nd_way | cat

我想知道为什么它在第二种方式中阻塞了 5 秒。

最佳答案

考虑这个脚本:

#!/bin/bash

main() {
cd /tmp
}

main > /dev/null
echo goodbye

bash 在运行main 函数之前,需要将自己的标准输出重定向到/dev/null。然后它需要运行 main 函数。然后,在执行 echo 命令之前,它需要将其标准输出恢复为重定向之前的状态。

这是它是如何做到的。为了进行重定向,它打开 /dev/null,获取(比方说)文件描述符 3。然后它将其文件描述符 1(标准输出)复制到第一个可用的 fd ≥ 10,获取(让我们说)10. 然后它复制 fd 3(在 /dev/null 上打开)到 fd 1,然后关闭 fd 3。

稍后,为了撤消重定向,它将 fd 10(在 bash 的原始标准输出上打开)复制到 fd 1,并关闭 fd 10。

好的,现在回到您的脚本。当你的脚本说 main >/dev/null 时,所有相同的事情都会发生,所以当 main 正在执行时,fd 10 在 shell 的原始标准输出上打开,这是管道的可写端到 cat

当您的 maindo_sth >/dev/null & 时,shell 会 fork 。子 shell 继承 fd 10,因此父 shell 和子 shell 都在管道上打开了 fd 10。 (注意 shell 知道它不需要在这里保存它的标准输出,因为 & 使它 fork 。)

当子 shell 在 do_sth 中运行 sleep 时,它 fork 运行 sleep 并等待 sleep 退出。所以子 shell 挂起五秒钟,在此期间它在管道的可写端打开了 fd 10。

cat 进程在可写端的所有文件描述符都关闭之前不会在管道的可读端读取 EOF,直到子 shell 退出时才会发生这种情况,而这不会'直到 sleep 退出。

关于bash - 为什么我的 bash 脚本会阻塞?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32900636/

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