如何在 Bash 中重试命令?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7449772/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to retry a command in Bash?
提问by stevejb
I have a command that should take less than 1 minute to execute, but for some reason has an extremely long built-in timeout mechanism. I want some bash that does the following:
我有一个命令执行时间应该不到 1 分钟,但由于某种原因,它有一个非常长的内置超时机制。我想要一些执行以下操作的 bash:
success = False
try(my_command)
while(!(success))
wait 1 min
if my command not finished
retry(my_command)
else
success = True
end while
How can I do this in Bash?
我怎样才能在 Bash 中做到这一点?
回答by Jonathan Leffler
Look at the GNU timeoutcommand. This kills the process if it has not completed in a given time; you'd simply wrap a loop around this to wait for the timeoutto complete successfully, with delays between retries as appropriate, etc.
查看 GNUtimeout命令。如果在给定时间内没有完成,这将终止进程;您只需在此周围环绕一个循环以等待timeout成功完成,并在重试之间适当延迟等。
while timeout -k 70 60 -- my_command; [ $? = 124 ]
do sleep 2 # Pause before retry
done
If you must do it in pure bash(which is not really feasible - bashuses lots of other commands), then you are in for a world of pain and frustration with signal handlers and all sorts of issues.
如果您必须纯粹地执行此操作bash(这实际上并不可行 -bash使用许多其他命令),那么您将面临信号处理程序和各种问题的痛苦和沮丧。
Please expand on your answer a little.
-k 70is--kill-after= 70seconds, 124 exit on timeout; what is the 60?
请稍微扩展您的答案。
-k 70是--kill-after= 70秒,124 超时退出;什么是60?
The linked documentation does explain the command; I don't really plan to repeat it all here. The synopsis is timeout [options] duration command [arg]...; one of the options is -k duration. The -k durationsays "if the command does not die after the SIGTERM signal is sent at 60 seconds, send a SIGKILL signal at 70 seconds" (and the command should die then). There are a number of documented exit statuses; 124 indicates that the command timed out; 137 that it died after being sent the SIGKILL signal, and so on. You can't tell if the command itself exits with one of the documented statuses.
链接的文档确实解释了命令;我真的不打算在这里重复这一切。概要是timeout [options] duration command [arg]...; 选项之一是-k duration。在-k duration说“如果SIGTERM信号在60秒后发送的命令不会死亡,在70秒发送SIGKILL信号”(以及命令应该然后死亡)。有许多记录在案的退出状态;124 表示命令超时;137 它在发送 SIGKILL 信号后死亡,依此类推。您无法判断命令本身是否以记录的状态之一退出。
回答by rhinoceros.xn
I found a script from: http://fahdshariff.blogspot.com/2014/02/retrying-commands-in-shell-scripts.html
我从以下位置找到了一个脚本:http: //fahdshariff.blogspot.com/2014/02/retrying-commands-in-shell-scripts.html
#!/bin/bash
# Retries a command on failure.
# - the max number of attempts
# ... - the command to run
retry() {
local -r -i max_attempts=""; shift
local -r cmd="$@"
local -i attempt_num=1
until $cmd
do
if ((attempt_num==max_attempts))
then
echo "Attempt $attempt_num failed and there are no more attempts left!"
return 1
else
echo "Attempt $attempt_num failed! Trying again in $attempt_num seconds..."
sleep $((attempt_num++))
fi
done
}
# example usage:
retry 5 ls -ltr foo
回答by tripleee
Adapting @Shin's answer to use kill -0rather than jobsso that this should work even with classic Bourne shell, and allow for other background jobs. You may have to experiment with killand waitdepending on how my_commandresponds to those.
调整@Shin 的答案以使用kill -0而不是jobs这样,即使使用经典的 Bourne shell 也能正常工作,并允许其他后台作业。您可能需要进行试验,kill并wait取决于对这些的my_command反应。
while true ; do
my_command &
sleep 60
if kill -0 $! 2>/dev/null; then
# Job took too long
kill $!
else
echo "Job is done"
# Reap exit status
wait $!
break
fi
done
回答by analogue
I liked @Jonathan's answer, but tried to make it more straight forward for future use:
我喜欢@Jonathan 的回答,但试图让它更直接以备将来使用:
until timeout 1 sleep 2
do
echo "Happening after 1s of sleep"
done
回答by Kilian Foth
You can run a command and retain control with the &background operator. Run your command in the background, sleepfor as long as you wish in the foreground, and then, if the background job hasn't terminated, kill it and start over.
您可以运行命令并保留&后台操作员的控制权。在后台运行您的命令,sleep只要您希望在前台运行,然后,如果后台作业尚未终止,请终止它并重新开始。
回答by Shizzmo
while true ; do
my_command &
sleep 60
if [[ $(jobs -r) == "" ]] ; then
echo "Job is done"
break
fi
# Job took too long
kill -9 $!
done
回答by J0hnG4lt
Using the "retrycli" tool you can get exponential backoff and retries on any bash script or tool (not bash functions though, unless they have been moved into another script which is then called by retry).
使用“retrycli”工具,您可以获得指数退避并在任何 bash 脚本或工具上重试(但不是 bash 函数,除非它们已移入另一个脚本,然后由重试调用)。
pip install git+git://github.com/sky-shiny/retrycli.git
retry my_command

