从shell写入fifo / pipe,超时

时间:2009-01-07 22:52:18

标签: shell timeout named-pipes

我有一对shell程序可以通过命名管道进行交谈。读者在启动时创建管道,并在管道退出时将其移除。

有时,编写者会尝试在读取器停止读取的时间和删除管道的时间之间写入管道。

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

但这有点蠢。是否有内置的shell或命令来更干净地执行此操作(不会破坏C编译器)?

4 个答案:

答案 0 :(得分:1)

这个问题会定期出现(虽然我无法通过搜索找到它)。我编写了两个用作超时命令的shell脚本:一个用于读取标准输入的内容,另一个用于不读取标准输入的内容。这很糟糕,我一直想写一个C程序,但我还没有解决它。我绝对建议一劳永逸地在C中编写timeout命令。但同时,这里有两个shell脚本的简单,如果命令读取标准输入,则会挂起:

#!/bin/ksh

# our watchdog timeout in seconds
maxseconds="$1"
shift

case $# in
  0) echo "Usage: `basename $0` <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/~nr/drop/timeout上线。

答案 1 :(得分:1)

处理此问题的UNIX“标准”方法是使用Expect,它带有定时运行示例:仅在给定时间内运行程序。

Expect可以为脚本创造奇迹,非常值得学习。如果您不喜欢Tcl,那么还有一个Python Expect模块。

答案 2 :(得分:0)

使用Unix域套接字而不是命名管道在Perl中重写后,这对程序运行得更好。这个问题中的特殊问题完全消失了,因为如果/当一端死亡时连接消失而不是挂起。

答案 3 :(得分:0)

trap 'kill $(ps -L $! -o pid=); exit 30' 30
echo kill -30 $$ 2\>/dev/null | at $1 2>/dev/null
shift; eval $@ &
wait