【问题标题】:Bash script not exiting immediately when `exit` is called调用“exit”时,Bash 脚本不会立即退出
【发布时间】:2023-11-04 02:01:01
【问题描述】:

我有以下 bash 脚本:

tail -F -n0 /private/var/log/system.log | while read line 
do
    if [ ! `echo $line | grep -c 'launchd'` -eq 0 ]; then
        echo 'launchd message'
        exit 0
    fi
done

由于某种原因,它正在回显launchd message,等待整整 5 秒,然后然后退出。

为什么会发生这种情况?如何在它回显launchd message 后立即退出?

【问题讨论】:

    标签: bash scripting exit terminate


    【解决方案1】:

    由于您使用的是管道,while 循环正在子外壳中运行。而是在主 shell 中运行它。

    #!/bin/bash
    
    while ...
    do
       ...
    done < <(tail ...)
    

    【讨论】:

    • 调用 bash 作为 sh 会禁用某些功能,包括进程替换。
    • +1,这有助于一个只有在脚本中运行时才会中断的四级管道。奇怪的东西。
    • 这完全从 Putty 中退出。有什么方法可以从 while 中退出吗?
    【解决方案2】:

    正如 Ignacio 所指出的,您的 tail | while 创建了一个子shell。延迟是因为它正在等待下一行在所有内容关闭之前写入日志文件。

    如果您不想使用进程替换,可以在 exit 命令之前立即添加此行:

    kill -SIGPIPE $$
    

    不幸的是,我不知道使用这种方法控制退出代码的任何方法。它将是 141,即 128 + 13(SIGPIPE 的信号编号)。

    如果您试图让一个守护进程的启动依赖于另一个已经启动的守护进程,那么可能有更好的方法来做到这一点。

    顺便说一句,如果您真的在编写 Bash 脚本(您必须使用 &lt;() 进程替换),您可以像这样编写您的 ifif [[ $line == *launchd* ]]

    【讨论】:

      【解决方案3】:

      您也可以使用退出代码退出子shell,然后测试“$?”的值获得您想要的相同效果:

      tail -F -n0 /private/var/log/system.log | while read line 
      do
          if [ ! `echo $line | grep -c 'launchd'` -eq 0 ]; then
              echo 'launchd message'
              exit 10
          fi
      done
      if [ $? -eq 10 ]; then exit 0; fi
      

      【讨论】: