简体   繁体   English

等待进程完成或用户输入

[英]Wait for process to finish, or user input

I have a backgrounded process that I would like to wait for (in case it fails or dies), unless I receive user input. 我有一个后台进程,我想等待(如果它失败或死亡),除非我收到用户输入。 Said another way, the user input should interrupt my waiting. 换句话说,用户输入应该中断我的等待。

Here's a simplified snippet of my code 这是我的代码的简化片段

#!/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

The line that I particularly dislike is sleep 10 , which is bad because it could be too much time, or not enough time. 我特别不喜欢的是sleep 10 ,这很糟糕,因为它可能是太多时间,或者时间不够。

Is there a way to wait $! || read 有没有办法wait $! || read wait $! || read wait $! || read or the equivalent? wait $! || read或等效?

Use kill -0 to validate that the process is still there and read with a timeout of 0 to test for user input. 使用kill -0验证进程是否仍在那里并以超时0 read以测试用户输入。 Something like this? 像这样的东西?

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

Original 原版的

ps -p to check the process. ps -p检查进程。 read -t 1 to wait for user input. 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

This allows for branching based whether the process died, or was killed due to user input. 这允许基于过程是否死亡或由于用户输入而被杀死的分支。


All credit to gubblebozer. 所有归功于gubblebozer。 The only reason I'm posting this answer is the claim by moderators that my edits to his post constituted altering his intent. 我发布此答案的唯一原因是主持人声称我对其帖子的编辑构成了改变他的意图。

Anti Race-Condition 反竞争条件

First off, a race condition involving pids is (very likely) not a concern if you're fairly quick, because they're reused on a cycle . 首先,如果你相当快,一个涉及pids的竞争条件(很可能)不是问题,因为它们会在一个循环中重复使用

Even so, I guess anything is possible... Here's some code that handles that possibility, without breaking your head on traps. 即便如此,我猜任何事都有可能......这里有一些处理这种可能性的代码,而不会破坏你的陷阱。

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

Now, we've accomplished our goal, while (probably) completely eliminating the race condition. 现在,我们已经完成了我们的目标,同时(可能)完全消除了竞争条件。

Any loop with a sleep or similar timeout in it, will introduce a race condition. 任何具有sleep或类似超时的循环都会引入竞争条件。 It's better to actively wait for the process to die, or, in this case, to trap the signal that's sent when a child dies. 最好主动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

I'm not 100% sure this eliminates any race condition, but it's a lot closer than a sleep loop. 我不是百分百肯定这可以消除任何竞争条件,但它比sleep循环更接近。

edit: the shorter, less verbose version 编辑:更短,更简洁的版本

#!/bin/bash

set -o monitor
trap exit SIGCHLD

sleep 5 &

read -p "hit enter: "
kill $!

edit 2: setting the trap before starting the background process prevents another race condition in which the process would die before the trap was installed 编辑2:在启动后台进程之前设置陷阱可防止进程在安装陷阱之前死亡的另一种竞争条件

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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