加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

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

发布时间:2020-12-15 19:03:30 所属栏目:安全 来源:网络整理
导读:我编写了一个运行命令的函数,它以两个args为第一个命令,以秒为单位的第二个超时: #! /bin/bashfunction run_cmd { cmd="$1"; timeout="$2" grep -qP "^d+$" "$timeout" || timeout=10 stderrfile=$(readlink /proc/$$/fd/2) exec 2- exitfile=/tmp/exit_$(
我编写了一个运行命令的函数,它以两个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会杀死错误的进程.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读