2015-07-01 3 views
3

У меня есть фоновый процесс, который я хотел бы ожидать (если он терпит неудачу или умрет), если только я не получаю пользовательский ввод. С другой стороны, пользовательский вход должен прерывать мое ожидание.Дождитесь завершения процесса или ввода пользователем

Вот упрощенный фрагмент моего кода

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

Используйте kill -0, чтобы проверить, что процесс все еще существует, и read с таймаутом 0 для проверки ввода пользователем. Что-то вроде этого?

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

Это очень плохое состояние гонки.Предположим, что процесс умирает во время сна, затем начинается другой процесс с тем же pid. Вы будете наблюдать за другим (случайным) процессом! – mvds

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. Единственная причина, по которой я отправляю этот ответ, - это утверждение модераторов о том, что мои изменения на его посту составили изменение его намерения.

Анти-Race Состояние

Во-первых, состояние гонки с участием ИДП является (весьма вероятно) не является проблемой, если вы достаточно быстро, потому что они 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

Это очень плохое состояние гонки. Предположим, что процесс замирает во время ожидания, затем запускается другой процесс с одним и тем же pid, а затем пользователь нажимает enter. Вы будете убивать случайный процесс. – mvds

+0

@mvds Интересно. Позвольте спросить. Если я скажу прямо «если ps -p $ pid; затем убить $ pid; fi', это гарантированно убить правильный процесс? –

+0

Все еще не полностью, вы должны принять другой подход. Лучше не «опросить» себя, а ждать сигнала. По многим причинам, кроме этого состояния гонки! См. Мой ответ. – mvds

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: установка ловушки перед началом процесса фона предотвращает другое условие гонки, в которой процесс будет умереть, прежде чем ловушка была установлена ​​

+0

Возможно, документы вводят в заблуждение, но 'monitor -m' кажется излишним, а' trap exit SIGCHILD' кажется неправильным. Кроме того, его запуск не приводит к ожидаемому поведению. Итак ... –

+0

Я не следую за тобой. Действительно, «ловушка выхода SIGCHILD» ошибочна из-за лишнего «я» вы добавили. В manpage говорится, что за «ловушкой» следует «команда». В manpage также указано, что 'exit' является' command'. Не могли бы вы рассказать о том, как это «кажется неправильным»? О «мониторе» вы можете быть правы. – mvds

+0

Вы правы в 'SIGCHLD' (не получилось найти его), но даже это не работает. Я потратил несколько часов на простые тестовые тесты, которые стали нигде. –

Смежные вопросы