优雅的解决方案,以实现对于bash命令和函数超时 [英] Elegant solution to implement timeout for bash commands and functions
问题描述
我写了一个函数来运行命令,其中有两个参数在1秒钟内指令第二超时:
#! /斌/庆典功能RUN_CMD {
CMD =$ 1;超时=$ 2
grep的-Qp^ \\ D $ +<<< $超时||超时= 10 stderrfile = $(的readlink的/ proc / $$ / FD / 2)
EXEC 2';&放大器; - exitfile =的/ tmp /退出_ $(日期+%S%N)
(EVAL$ CMD;回声$> $ exitfile)及 启动= $(日期+%S)
而真实的;做
PID = $(工种-l | awk的'/运行/ {打印$ 2})
如果[-n$ PID];然后
现在= $(日期+%S)
运行= $(($现在 - $开始))
如果[$运行-ge$超时];然后
杀-15$ PID
退出= 1
科幻
睡眠1
其他
打破
科幻 DONE
测试-n$退出||退出= $(猫$ exitfile)
RM $ exitfile
EXEC 2 - ; $ stderrfile
回归$退出
}
功能sleep5 {
睡眠5
回声我睡5
返回2
}RUN_CMD sleep56
RUN_CMD sleep53
回声嗨>和2
该功能工作正常,但我不知道它是一个完美的解决方案,我想知道关于替代以下
- 我有存储上的文件退出状态:
(?的eval$ CMD;回声$> $ exitfile)
- 我关闭并重新打开STDERR:
EXEC 2';&安培; - 和exec 2 - ; $ stderrfile
我将结束STDERR因为杀死命令时,我无法避免的消息:
test.sh:3号线:32323终止(?的eval$ CMD;回声$> $ exitfile)
PS:我知道暂停
和期望
,但他们不会为职能的工作。
这也许适合您的需要。我改变了调用签名,以使其能够避免使用评估
。
#用法:run_with_timeoutñCMD ARGS ...
#或:run_with_timeout CMD ARGS ...
#在第二种情况下,CMD不能是数目和超时将为10秒。
run_with_timeout(){
本地时间= 10
如果[[$ 1 =〜^ [0-9] + $]];然后时间= $ 1;转移;科幻
在子shell来避免作业控制信息#执行
($ @&放大器;
孩子= $!
在非交互的shell为SIGTERM#避免违约通知
陷阱 - SIGTERM
(睡眠时间$
杀死孩子$ 2 - ;的/ dev / null的)及
等待$孩子
)
}
例子,显示退出状态:
$ sleep_and_exit(){$睡眠{1:-1};退出$ {2:-0}; }$时间run_with_timeout 1 sleep_and_exit 3 0;回声$?真正0m1.007s
用户0m0.003s
SYS 0m0.006s
143$时间run_with_timeout 3 sleep_and_exit 1 0;回声$?真正0m1.007s
用户0m0.003s
SYS 0m0.008s
0$时间run_with_timeout 3 sleep_and_exit 1 7;回声$?真正0m1.006s
用户0m0.001s
SYS 0m0.006s
7
如图所示, run_with_timeout
的退出状态将是执行命令的退出状态,除非它是由超时,在这种情况下,这将是143(128丧生+ 15)。
请注意:如果您设置一个较大的超时和/或具有forkbomb运行,则可能回收的PID速度不够快杀儿杀死了错误的过程
。I wrote a function to run commands, which takes two args 1st a command 2nd timeout in seconds:
#! /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
The function works fine but I am not sure it's an elegant solution, I would like to know about alternatives for the following
- I am having to store exit status on a file:
(eval "$cmd";echo $? > $exitfile)
- I am closing and reopening STDERR:
exec 2<&- and exec 2>$stderrfile
I am closing STDERR because I couldn't avoid the message when killing the command:
test.sh: line 3: 32323 Terminated ( eval "$cmd"; echo $? > $exitfile )
PS: I am aware of timeout
and expect
but they wouldn't work for functions.
Perhaps this suits your needs. I changed the call signature to make it possible to avoid using 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
)
}
Example, showing exit status:
$ 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
As shown, the exit status of run_with_timeout
will be the exit status of the executed command unless it was killed by the timeout, in which case it will be 143 (128 + 15).
Note: If you set a large timeout and/or have a forkbomb running, you might recycle pids fast enough that the kill-child kills the wrong process.
这篇关于优雅的解决方案,以实现对于bash命令和函数超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!