2015-10-02 40 views
7

我有一个bash脚本:my.sh为什么我的bash脚本被阻塞?

#!/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秒。

回答

5

考虑这个脚本:

#!/bin/bash 

main() { 
    cd /tmp 
} 

main > /dev/null 
echo goodbye 

庆典之前运行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继承fd 10,因此父级和子级shell都在管道上打开了fd 10。 (请注意,外壳知道,它并不需要在这里保存它的标准输出,因为&的使它叉。)

当孩子外壳,do_sth,运行sleep,它叉运行sleep并等待sleep退出。所以孩子的外壳挂了五秒钟,在那段时间里,在管道的可写端有10个打开。

cat进程不会读取管道可读端的EOF,直到可写端上的所有文件描述符都关闭,直到退出子shell才会发生,直到退出sleep才会发生。

相关问题