我有一个后台程序,我想等待(如果它失败或死亡),除非我收到用户输入。换句话说,用户输入应该中断我的等待。
以下是我的代码的简化代码段
#!/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
或同等的?
答案 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:在开始后台进程之前设置陷阱可防止在安装陷阱之前进程将死亡的另一种竞争条件