繁体   English   中英

等待进程完成或用户输入

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM