等待进程完成或用户输入

时间:2015-07-01 17:41:18

标签: bash

我有一个后台程序,我想等待(如果它失败或死亡),除非我收到用户输入。换句话说,用户输入应该中断我的等待。

以下是我的代码的简化代码段

#!/bin/bash
...

mplayer -noconsolecontrols "$media_url" &
sleep 10 # enough time for it to fail

ps -p $!
if [ $? -ne 0 ]
then
    fallback
else
    read
    kill $!
fi

我特别不喜欢的是sleep 10,这很糟糕,因为时间太长或时间不够。

有没有办法wait $! || read或同等的?

3 个答案:

答案 0 :(得分:3)

使用kill -0验证进程是否仍然存在以及read超时为0以测试用户输入。像这样的东西?

pid=$!
while kill -0 $pid; do
    read -t 0 && exit
    sleep 1
done

答案 1 :(得分:2)

<强>原始

ps -p检查流程。 read -t 1等待用户输入。

pid=$!
got_input=142
while ps -p $pid > /dev/null; do
    if read -t 1; then
        got_input=$?
        kill $pid
    fi
done

这允许基于流程是否死亡或由于用户输入而被杀死的分支。

归功于gubblebozer。我发布此答案的唯一原因是主持人声称我对其帖子的编辑构成了改变他的意图。

反竞赛条件

首先,如果你相当快,一个涉及pids的竞争条件(很可能)不是问题,因为他们会reused on a cycle

即便如此,我猜任何事都有可能......这里有一些处理这种可能性的代码,而不会破坏你的陷阱。

got_input=142

while true; do
    if read -t 1; then
        got_input=$?
        pkill --ns $$ name > /dev/null
        break
    elif ! pgrep --ns $$ name > /dev/null; then
        break
    fi
done

现在,我们已经完成了我们的目标,同时(可能)完全消除了竞争条件。

答案 2 :(得分:0)

任何带有sleep或类似超时的循环都会引入竞争条件。积极wait让死亡过程更好,或者,在这种情况下,捕获孩子死亡时发出的信号。

#!/bin/bash

set -o monitor
trap stop_process SIGCHLD
stop_process()
{
    echo sigchld received
    exit
}

# the background process: (this simulates a process that exits after 10 seconds)
sleep 10 &

procpid=$!
echo pid of process: $procpid

echo -n hit enter: 
read

# not reached when SIGCHLD is received
echo killing pid $procpid
kill $procpid

我并非100%确定这可以消除任何竞争条件,但它比sleep循环更接近。

编辑:更短,更简洁的版本

#!/bin/bash

set -o monitor
trap exit SIGCHLD

sleep 5 &

read -p "hit enter: "
kill $!

编辑2:在开始后台进程之前设置陷阱可防止在安装陷阱之前进程将死亡的另一种竞争条件