【问题标题】:How do I receive notification in a bash script when a specific child process terminates?当特定子进程终止时,如何在 bash 脚本中接收通知?
【发布时间】:2012-10-05 17:54:27
【问题描述】:

我想知道是否有人可以帮助解决这个问题?

我有一个 bash 脚本。它启动一个子进程,这是另一个基于 gui 的应用程序。然后 bash 脚本进入交互模式,从用户那里获取输入。这种交互模式无限期地继续下去。我希望它在子进程中的 gui 应用程序退出时终止。

我看过 SIGCHLD 但这似乎不是答案。这是我尝试过的,但是当 prog 结束时我没有收到信号。

set -o monitor

"${prog}" &
prog_pid=$!

function check_pid {
    kill -0 $1 2> /dev/null
}

function cleanup {
    ### does cleanup stuff here
    exit
}


function sigchld {
    check_pid $prog_pid
    [[ $? == 1 ]] && cleanup
}

trap sigchld SIGCHLD

更新了以下答案。我现在可以使用“nosid”的建议进行这项工作。我现在有另一个相关的问题,即接下来的交互过程是一个基本的菜单驱动过程,它阻止等待用户的键输入。如果子进程结束,则在接收到输入之前不处理 USR1 信号。有什么办法可以强制立即处理信号?

等待的样子是这样的:

stty raw                 # set the tty driver to raw mode 
max=$1                   # maximum valid choice
choice=$(expr $max + 1)  # invalid choice
while [[ $choice -gt $max ]]; do
    choice=`dd if=/dev/tty bs=1 count=1 2>/dev/null`
done
stty sane                # restore tty

已更新解决方案。我已经解决了这个问题。诀窍是使用非阻塞 I/O 进行读取。现在,有了“nosid”的答案和我的修改,我得到了我想要的。为了完整起见,这对我有用:

#!/bin/bash -bm
{
"${1}"
kill -USR1 $$
} &

function cleanup {
    # cleanup stuff
    exit
}

trap cleanup SIGUSR1

while true ; do
   stty raw                 # set the tty driver to raw mode 
   max=9                    # maximum valid choice
   while [[ $choice -gt $max || -z $choice ]]; do
       choice=`dd iflag=nonblock if=/dev/tty bs=1 count=1 2>/dev/null`
   done
   stty sane                # restore tty

   # process choice       

done

【问题讨论】:

  • 附带说明,bash 算术是使用(( 完成的,例如:while (( choice > max )); do ...

标签: bash nonblocking child-process sigchld


【解决方案1】:

这是一种不同的方法。您可以在 GUI 应用程序终止后立即执行任意命令,而不是使用 SIGCHLD。

{
    some_command args...
    kill -USR1 $$
} &

function sigusr1() { ... }

trap sigusr1 SIGUSR1

【讨论】:

  • 谢谢你,它对我有用(几乎)。我还需要将 -bm 添加到 shebang。我现在有另一个问题,我在原始问题中进行了更新。
【解决方案2】:

好的。我想我明白你需要什么。看看我的 .xinitrc:

   xrdb ~/.Xdefaults
   source ~/.xinitrc.hw.settings
   xcompmgr &
   xscreensaver &
   # after starting some arbitrary crap we want to start the main gui.       

   startfluxbox &  PIDOFAPP=$! ## THIS IS THE IMPORTANT PART
   setxkbmap genja

   wmclockmon -bl &


   sleep 1
   wmctrl -s 3  && aterms sone &
   sleep 1
   wmctrl -s 0


   wait $PIDOFAPP ## THIS IS THE SECOND PART OF THE IMPORTANT PART

   xeyes -geometry 400x400+500+400 &
   sleep 2
   echo im out!

发生的情况是,在将进程发送到后台后,您可以使用 wait 等到进程终止。只要应用程序正在运行,等待之后的任何内容都不会执行。在 GUI 关闭后,您可以使用它退出。

PS:我运行 bash。

【讨论】:

  • 在这种情况下等待是不合适的,因为原始脚本需要在子进程处于活动状态时继续工作。
  • bash 中的等待与 java.Object.wait() 不同
【解决方案3】:

我认为你需要这样做:

set -bm

或

set -o monitor notify

根据bash manual:

-b
    Cause the status of terminated background jobs to be reported immediately, rather than before printing the next primary prompt.

【讨论】:

  • 是的,需要 -bm。您也可以将其添加到 shebang,如下所示:“#!/bin/bash -bm”。我猜你怎么做取决于个人喜好。
【解决方案4】:

shell 的主要工作是执行子进程,并且 它需要为自己的目的捕获 SIGCHLD。这以某种方式限制了它将信号传递给脚本本身。

您能否只检查孩子pid 并在此基础上发送警报。您可以在下面找到孩子pid-

bash_pid=$$
while true
do
    children=`ps -eo ppid | grep -w $bash_pid`
    if [ -z "$children" ]; then
        cleanup
        alert
        exit
    fi
done

【讨论】:

    猜你喜欢
    • 2011-12-10
    • 1970-01-01
    • 1970-01-01
    • 2010-10-06
    • 2012-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多