【问题标题】:When piping a command to shell script, why does exiting piped command makes shell script exit?将命令管道传输到 shell 脚本时,为什么退出管道命令会使 shell 脚本退出?
【发布时间】:2018-05-27 11:16:40
【问题描述】:

首先,对不起,如果标题不明确或误导,我的问题并不是很容易脱离上下文理解。

就是这样:我正在运行一个 shell 脚本 (hello.sh),它需要将自身从 /root 重新定位到 /。 因此我做了一个简单的递归,以测试脚本从哪里运行并制作一个临时副本并启动它并退出(最后一个临时副本将移动原始文件,并在仍在运行时自行删除)。

#!/bin/sh    

IsTMP=$(echo $0 | grep "tmp")
if [ -z "$IsTMP" ]; then
        cp /root/hello.sh /tmp/hello.sh
        /bin/sh /tmp/hello.sh &
        exit
else
        unlink /hello.sh
        rsync /root/hello.sh /hello.sh
        rm /root/hello.sh
        rm /tmp/hello.sh
fi


while true; do
        sleep 5
        echo "Still Alive"
done

这个脚本运行良好并且符合我的需要(尽管它是一个可怕的 hack):脚本被移动,并从一个临时位置重新执行。但是,当我使用 tee 管道传输 shell 脚本时,就像:

/hello.sh | tee -a /log&

行为不一样:

  • hello.sh 正在退出,但未退出 tee
  • 当我尝试杀死 tee 时,临时副本会在几秒钟后自动杀死,不会进入无限循环

如果我用另一个二进制文件(例如手表,...)替换 tee,这种行为是完全相同的,所以我想知道它是否来自管道。

对不起,如果我不太清楚我的问题。 提前致谢。

【问题讨论】:

  • 我怀疑您的后台进程 hello.sh 导致 tee 挂起。您可能想尝试将其输出重定向到/dev/null。如果我理解正确,后台进程会进入无限循环,因此永远不会退出。连接到其父标准输出肯定会导致 tee 永远不会退出。
  • 我不确定你在最后一句中的意思。这就是我观察到的执行 /hello.sh | tee -a /log&: • 第一个 ps -> tee 和第一个 hello.sh 实例都处于活动状态 1762 root 0:00 {hello.sh} /bin/sh /hello.sh 1763 root 0:00 tee -a /log • 第二个ps -> hello.sh(来自/root)的第一个实例已退出,tmp 实例已启动,tee 仍在此处。 1207 1763 tee tee -a /log 1 1773 sh /bin/sh /tmp/hello.sh tee 和第二个实例之间没有联系,因为 ppid 和 pid 不同。但是当我杀死 tee 时,来自 tmp 的 hello.sh 也会退出。

标签: linux shell sh


【解决方案1】:

当我尝试杀死tee时,临时副本会在几秒钟后自动杀死,不会进入无限循环

事实并非如此。脚本进入无限循环几秒是循环中的五个sleep 5暂停,然后被杀死信号 SIGPIPE (Broken pipe) 因为它试图将echo "Still Alive" 连接到由于tee 已被杀死而在读取端关闭的管道。

tee和第二个实例之间没有联系

事实并非如此。有一个链接,即管道,它的写端是父shell脚本以及(继承)子shell脚本的标准输出,读端是tee的标准输入。如果您查看 ls -l /proc/<i>pid</i>/fd,您可以看到这一点,其中 pid 一方面是脚本 shell 的进程 ID,另一方面是 tee 的进程 ID。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-01
    • 2013-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多