为bash命令和函数实现超时的优雅解决方案

前端之家收集整理的这篇文章主要介绍了为bash命令和函数实现超时的优雅解决方案前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我编写了一个运行命令的函数,它以两个args为第一个命令,以秒为单位的第二个超时:
#! /bin/bash

function run_cmd {
    cmd="$1"; timeout="$2"
    grep -qP "^\d+$" <<< "$timeout" || timeout=10

    stderrfile=$(readlink /proc/$$/fd/2)
    exec 2<&-

    exitfile=/tmp/exit_$(date +%s.%N)
    (eval "$cmd";echo $? > $exitfile) &

    start=$(date +%s)
    while true; do
        pid=$(jobs -l | awk '/Running/{print $2}')
        if [ -n "$pid" ]; then
            now=$(date +%s)
            running=$(($now - $start))
            if [ "$running" -ge "$timeout" ];then
                kill -15 "$pid"
                exit=1
            fi
            sleep 1
        else
            break
        fi

    done 
    test -n "$exit" || exit=$(cat $exitfile)
    rm $exitfile
    exec 2>$stderrfile              
    return "$exit"
}


function sleep5 {
    sleep 5
    echo "I slept 5"
    return 2
}

run_cmd sleep5 "6" 
run_cmd sleep5 "3"
echo "hi" >&2

功能工作正常但我不确定它是一个优雅的解决方案,我想知道以下的替代品

>我必须将退出状态存储在文件中:( eval“$cmd”; echo $?> $exitfile)
>我正在关闭并重新打开STDERR:exec 2<& - 和exec 2> $stderrfile

我正在关闭STDERR因为我在杀死命令时无法避免该消息:

test.sh:第3行:32323终止(eval“$cmd”; echo $?> $exitfile)

PS:我知道超时和期望,但他们不适用于功能.

也许这适合您的需求.我更改了呼叫签名,以避免使用eval.
# Usage: run_with_timeout N cmd args...
#    or: run_with_timeout cmd args...
# In the second case,cmd cannot be a number and the timeout will be 10 seconds.
run_with_timeout () { 
    local time=10
    if [[ $1 =~ ^[0-9]+$]]; then time=$1; shift; fi
    # Run in a subshell to avoid job control messages
    ( "$@" &
      child=$!
      # Avoid default notification in non-interactive shell for SIGTERM
      trap -- "" SIGTERM
      ( sleep $time
        kill $child 2> /dev/null ) &
      wait $child
    )
}

示例,显示退出状态:

$sleep_and_exit() { sleep ${1:-1}; exit ${2:-0}; }

$time run_with_timeout 1 sleep_and_exit 3 0; echo $?

real    0m1.007s
user    0m0.003s
sys     0m0.006s
143

$time run_with_timeout 3 sleep_and_exit 1 0; echo $?

real    0m1.007s
user    0m0.003s
sys     0m0.008s
0

$time run_with_timeout 3 sleep_and_exit 1 7; echo $?

real    0m1.006s
user    0m0.001s
sys     0m0.006s
7

如图所示,run_with_timeout的退出状态将是执行命令的退出状态,除非它被超时杀死,在这种情况下它将是143(128 15).

注意:如果设置了一个大的超时和/或运行了一个forkbomb,你可能会以足够快的速度回收pid,kill-child会杀死错误的进程.

原文链接:https://www.f2er.com/bash/387182.html

猜你在找的Bash相关文章