【问题标题】:write to fifo/pipe from shell, with timeout从 shell 写入 fifo/pipe,超时
【发布时间】:2009-01-07 22:52:18
【问题描述】:

我有一对通过命名管道进行通信的 shell 程序。阅读器在启动时创建管道,并在退出时将其删除。

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

reader: while condition; do read data <$PIPE; do_stuff; done
writer: echo $data >>$PIPE
reader: rm $PIPE

当这种情况发生时,作家将永远挂起试图打开管道进行写作。

有没有一种 clean 方法让它超时,这样它就不会一直挂起,直到被手动杀死?我知道我能做到

#!/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 编译器)?

【问题讨论】:

    标签: shell timeout named-pipes


    【解决方案1】:

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

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

    【讨论】:

    • 不幸的是,该服务器似乎没有安装 Tcl 或 Python (AIX 5.2)。因此,虽然这听起来不错,但对我没有帮助。 :(
    • 一个不错的直接链接到上述 Expect 示例:expect.nist.gov/example/timed-run
    【解决方案2】:

    这个问题会定期出现(虽然我无法通过搜索找到它)。我编写了两个 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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:
        trap 'kill $(ps -L $! -o pid=); exit 30' 30
        echo kill -30 $$ 2\>/dev/null | at $1 2>/dev/null
        shift; eval $@ &
        wait
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-04
          • 1970-01-01
          • 2012-04-09
          相关资源
          最近更新 更多