[英]Wait for process to finish, or user input
我有一个后台进程,我想等待(如果它失败或死亡),除非我收到用户输入。 换句话说,用户输入应该中断我的等待。
这是我的代码的简化片段
#!/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
wait $! || read
wait $! || read
或等效?
使用kill -0
验证进程是否仍在那里并以超时0 read
以测试用户输入。 像这样的东西?
pid=$!
while kill -0 $pid; do
read -t 0 && exit
sleep 1
done
原版的
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的竞争条件(很可能)不是问题,因为它们会在一个循环中重复使用 。
即便如此,我猜任何事都有可能......这里有一些处理这种可能性的代码,而不会破坏你的陷阱。
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
现在,我们已经完成了我们的目标,同时(可能)完全消除了竞争条件。
任何具有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
我不是百分百肯定这可以消除任何竞争条件,但它比sleep
循环更接近。
编辑:更短,更简洁的版本
#!/bin/bash
set -o monitor
trap exit SIGCHLD
sleep 5 &
read -p "hit enter: "
kill $!
编辑2:在启动后台进程之前设置陷阱可防止进程在安装陷阱之前死亡的另一种竞争条件
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.