написать в fifo / pipe из оболочки с таймаутом
-
05-07-2019 - |
Вопрос
У меня есть пара программ оболочки, которые общаются по именованному каналу. Считыватель создает канал при запуске и удаляет его при выходе.
Иногда писатель пытается записать в канал между временем, когда читатель прекращает чтение, и временем, когда он удаляет канал.
reader: while condition; do read data <$PIPE; do_stuff; done
writer: echo $data >>$PIPE
reader: rm $PIPE
когда это произойдет, писатель будет висеть вечно, пытаясь открыть канал для записи.
Есть ли чистый способ дать ему тайм-аут, чтобы он не зависал до тех пор, пока его не убьют вручную? Я знаю, что могу сделать
#!/bin/sh
# timed_write <timeout> <file> <args>
# like "echo <args> >> <file>" with a timeout
TIMEOUT=$1
shift;
FILENAME=$1
shift;
PID=$
(X=0; # don't do "sleep $TIMEOUT", the "kill %1" doesn't kill the sleep
while [ "$X" -lt "$TIMEOUT" ];
do sleep 1; X=$(expr $X + 1);
done; kill $PID) &
echo "$@" >>$FILENAME
kill %1
но это отчасти неприлично. Есть ли встроенная оболочка или команда, делающая это более аккуратно (без использования компилятора C)?
Решение 3
Эта пара программ работает намного лучше после того, как она была переписана на Perl с использованием доменных сокетов Unix вместо именованных каналов. Конкретная проблема в этом вопросе полностью исчезла, поскольку, если / когда один конец умирает, соединение исчезает, а не зависает.
Другие советы
UNIX " стандарт " способ справиться с этим - использовать Expect , который поставляется с примером запуска по времени: запускать программу только для определенное количество времени.
Expect может творить чудеса со сценариями, которые стоит изучить. Если вам не нравится Tcl, есть также Python Expect .
Этот вопрос периодически возникает (хотя я не смог найти его с помощью поиска). Я написал два сценария оболочки для использования в качестве команд тайм-аута: один для вещей, которые читают стандартный ввод, и другой для вещей, которые не читают стандартный ввод. Это воняет, и я намеревался написать программу на C, но я еще не дошел до этого. Я определенно рекомендую написать команду timeout
на C раз и навсегда. Но тем не менее, вот более простой из двух сценариев оболочки, который зависает, если команда читает стандартный ввод:
#!/bin/ksh
# our watchdog timeout in seconds
maxseconds="$1"
shift
case $# in
0) echo "Usage: `basename <*>` <seconds> <command> [arg ...]" 1>&2 ;;
esac
"$@" &
waitforpid=$!
{
sleep $maxseconds
echo "TIMED OUT: $@" 1>&2
2>/dev/null kill -0 $waitforpid && kill -15 $waitforpid
} &
killerpid=$!
>>/dev/null 2>&1 wait $waitforpid
# this is the exit value we care about, so save it and use it when we
rc=$?
# zap our watchdog if it's still there, since we no longer need it
2>>/dev/null kill -0 $killerpid && kill -15 $killerpid
exit $rc
Другой сценарий доступен по адресу http: //www.cs.tufts. Edu / ~ Н.Р. / падение / тайм-аут .
trap 'kill $(ps -L $! -o pid=); exit 30' 30
echo kill -30 $ 2\>/dev/null | at $1 2>/dev/null
shift; eval $@ &
wait