【问题标题】:How to suppress Terminated message after killing in bash?在bash中杀死后如何抑制终止消息?
【发布时间】:2021-02-25 00:40:07
【问题描述】:

你怎么能抑制你杀死一个后出现的Terminated消息 在 bash 脚本中处理?

我试过set +bm,但没用。

我知道另一种解决方案涉及调用exec 2> /dev/null,但那是 可靠的?如何重置它以便我可以继续看到 stderr?

【问题讨论】:

标签: bash unix shell


【解决方案1】:

为了使消息静音,您必须在生成消息时重定向stderr。因为kill命令发送信号并且不等待目标进程响应,重定向kill命令的stderr对你没有好处。 bash 内置 wait 是专门为此目的而制作的。

这是一个非常简单的示例,可以杀死最近的后台命令。 (Learn more about $! here.)

kill $!
wait $! 2>/dev/null

因为killwait 都接受多个pid,你也可以进行批量杀戮。这是一个杀死所有后台进程(当然是当前进程/脚本)的示例。

kill $(jobs -rp)
wait $(jobs -rp) 2>/dev/null

我是从bash: silently kill background function process 被带到这里的。

【讨论】:

  • 很酷,但是它将退出状态($?)设置为一些奇怪的值
  • @AlexanderShcheblikin wait 返回后台进程的退出代码,或 128 +(杀死它的信号数)。
  • 这通常是错误的。该消息不是在wait 生成,而是在wait_for()jobs.c)被调用时生成,这意味着它可能在any 前台作业完成时生成。试试这个:sleep 10 & kill %1; sleep 0; wait 2>/dev/null。在这方面,wnoise 的回答大多是正确的。完全压制消息的唯一方法是执行exec 2>/dev/null,其后果显而易见。
【解决方案2】:

简短的回答是你不能。 Bash 总是打印前台作业的状态。监控标志仅适用于后台作业,并且仅适用于交互式 shell,不适用于脚本。

请参阅 jobs.c 中的 notify_of_job_status()。

正如您所说,您可以重定向,因此标准错误指向 /dev/null 但是您会错过任何其他错误消息。您可以通过在运行脚本的子外壳中进行重定向来使其成为临时的。这样就只剩下原始环境了。

(script 2> /dev/null)

这将丢失所有错误消息,但只是来自该脚本,而不是来自该 shell 中运行的任何其他内容。

您可以通过将新的文件描述符重定向到那里来保存和恢复标准错误:

exec 3>&2          # 3 is now a copy of 2
exec 2> /dev/null  # 2 now points to /dev/null
script             # run script with redirected stderr
exec 2>&3          # restore stderr to saved
exec 3>&-          # close saved version

但我不建议这样做——与第一个相比,唯一的好处是它节省了子 shell 调用,同时更复杂,如果脚本改变文件描述符,甚至可能改变脚本的行为.


编辑:

更合适的答案查看Mark Edgar给出的答案

【讨论】:

  • 我在 shell 脚本中启动了一个后台进程。杀死它时,我收到“终止”消息。我不明白你在子shell中临时重定向stderr是什么意思。这是否意味着它不会影响脚本,因为它是在子shell中完成的?因此在我的脚本中不起作用?
  • 这个答案是错误的。请参阅下面 Mark Edgar 的答案。
【解决方案3】:

解决方案:使用 SIGINT(仅适用于非交互式 shell)

演示:

cat > silent.sh <<"EOF"
sleep 100 &
kill -INT $!
sleep 1
EOF

sh silent.sh

http://thread.gmane.org/gmane.comp.shells.bash.bugs/15798

【讨论】:

    【解决方案4】:

    也许可以通过调用disown将进程与当前shell进程分离?

    【讨论】:

    • disown 暗示 shell 在终止时不会将 SIGHUP 发送给孩子,请参阅 this question。这是answer
    【解决方案5】:

    这是我们都在寻找的吗?

    不想要:

    $ sleep 3 &
    [1] 234
    <pressing enter a few times....>
    $
    $
    [1]+  Done                    sleep 3
    $
    

    通缉:

    $ (set +m; sleep 3 &)
    <again, pressing enter several times....>
    $
    $
    $
    $
    $
    

    如您所见,没有作业结束消息。在 bash 脚本中也适用于我,也适用于终止的后台进程。

    'set +m' 禁用当前 shell 的作业控制(参见 'help set')。因此,如果您在子 shell 中输入命令(如在括号中所做的那样),您将不会影响当前 shell 的作业控制设置。唯一的缺点是,如果要检查后台进程是否已终止或评估返回码,则需要将后台进程的 pid 返回到当前 shell。

    【讨论】:

    • 你为什么要set +m子shell?此外,接受的答案已经提供了您提供的信息。
    • 正如马蒂亚斯所暗示的,这个答案是不正确的。 Bash 不显示在子 shell 中执行的命令的作业控制消息,因此为此设置监视模式是无用的。 (set +m; sleep 3 &amp;) 将产生与(sleep 3 &amp;) 完全相同的效果。
    【解决方案6】:

    这也适用于 killall(对于那些喜欢它的人):

    killall -s SIGINT (yourprogram) 
    

    抑制消息...我在后台模式下运行 mpg123。 它只能通过发送 ctrl-c (SIGINT) 而不是 SIGTERM(默认)静默地被杀死。

    【讨论】:

    • 程序对不同信号的准确反应也是该程序的一个重要特征。
    【解决方案7】:

    Terminated 由 bash 3.x 和 4.x 的默认信号处理程序记录。只需在子进程的第一个捕获 TERM 信号:

    #!/bin/sh
    
    ## assume script name is test.sh
    
    foo() {
      trap 'exit 0' TERM ## here is the key
      while true; do sleep 1; done
    }
    
    echo before child
    ps aux | grep 'test\.s[h]\|slee[p]'
    
    foo &
    pid=$!
    
    sleep 1 # wait trap is done
    
    echo before kill
    ps aux | grep 'test\.s[h]\|slee[p]'
    
    kill $pid ## no need to redirect stdin/stderr
    
    sleep 1 # wait kill is done
    
    echo after kill
    ps aux | grep 'test\.s[h]\|slee[p]'
    
    

    【讨论】:

      【解决方案8】:

      disown 对我来说是完全正确的—— exec 3>&2 有很多风险—— set +bm 似乎在脚本中不起作用,只能在命令提示符下使用

      【讨论】:

      • disown 暗示 shell 在终止时不会将 SIGHUP 发送给孩子,请参阅 this question。这是answer
      【解决方案9】:

      成功地将“jobs 2&gt;&amp;1 &gt;/dev/null”添加到脚本中,不确定它是否会帮助其他人的脚本,但这里有一个示例。

          while true; do echo $RANDOM; done | while read line
          do
          echo Random is $line the last jobid is $(jobs -lp)
          jobs 2>&1 >/dev/null
          sleep 3
          done
      

      【讨论】:

        【解决方案10】:

        另一种禁用作业通知的方法是将您的命令置于sh -c 'cmd &amp;' 构造中。

        #!/bin/bash
        # ...
        pid="`sh -c 'sleep 30 & echo ${!}' | head -1`"
        kill "$pid"
        # ...
        
        # or put several cmds in sh -c '...' construct
        sh -c '
        sleep 30 &
        pid="${!}"
        sleep 5 
        kill "${pid}"
        '
        

        【讨论】:

          【解决方案11】:

          我发现将 kill 命令放在一个函数中,然后将该函数置于后台会抑制终止输出

          function killCmd() {
              kill $1
          }
          
          killCmd $somePID &
          

          【讨论】:

          • Nope 不起作用:当子进程终止时,bash 仍然会在第一次机会输出消息。
          【解决方案12】:

          简单:

          { kill $! } 2>/dev/null
          

          优势?可以使用任何信号

          例如:

          { kill -9 $PID } 2>/dev/null
          

          【讨论】:

          • kill(-9 除外)发送信号并且不等待响应。如果这对您有用,它会通过竞争条件来实现。我还看到代码从 { kill $! } 2&gt;/dev/null{ kill $!; date } 2&gt;/dev/null{ kill $!; sleep 5 } 2&gt;/dev/null 请参阅 Mark Edgar 的答案,了解如何正确执行此操作。
          猜你喜欢
          • 1970-01-01
          • 2018-05-09
          • 1970-01-01
          • 1970-01-01
          • 2018-10-31
          • 1970-01-01
          • 1970-01-01
          • 2016-11-11
          • 1970-01-01
          相关资源
          最近更新 更多