ฉันต้องการเขียนตรรกะในเชลล์สคริปต์ซึ่งจะลองอีกครั้งเพื่อให้ทำงานอีกครั้งหลังจาก 15 วินาทีนานถึง 5 ครั้งโดยอ้างอิงจาก"status code = FAIL"หากล้มเหลวเนื่องจากปัญหาบางอย่าง
ฉันต้องการเขียนตรรกะในเชลล์สคริปต์ซึ่งจะลองอีกครั้งเพื่อให้ทำงานอีกครั้งหลังจาก 15 วินาทีนานถึง 5 ครั้งโดยอ้างอิงจาก"status code = FAIL"หากล้มเหลวเนื่องจากปัญหาบางอย่าง
คำตอบ:
สคริปต์นี้ใช้ตัวนับn
เพื่อจำกัดความพยายามที่คำสั่งถึงห้า หากคำสั่งประสบความสำเร็จ$?
จะถือเป็นศูนย์และการดำเนินการจะหยุดลง
n=0
until [ $n -ge 5 ]
do
command && break # substitute your command here
n=$[$n+1]
sleep 15
done
if command; then break; fi
สั้นหรือกระชับกว่านั้นคือcommand && break
n
ผิดพลาดมันไม่จำเป็นต้องนอนเพิ่มอีกหนึ่งครั้งก่อนที่จะออก
for i in 1 2 3 4 5; do command && break || sleep 15; done
แทนที่ "คำสั่ง" ด้วยคำสั่งของคุณ นี่คือการสันนิษฐานว่า "รหัสสถานะ = FAIL" หมายถึงรหัสส่งคืนที่ไม่เป็นศูนย์
การใช้{..}
ไวยากรณ์ ใช้งานได้ในเชลล์ส่วนใหญ่ แต่ไม่ใช่ BusyBox sh
:
for i in {1..5}; do command && break || sleep 15; done
การใช้seq
และการส่งรหัสทางออกของคำสั่งที่ล้มเหลว:
for i in $(seq 1 5); do command && s=0 && break || s=$? && sleep 15; done; (exit $s)
เหมือนด้านบน แต่ข้ามsleep 15
หลังจากความล้มเหลวครั้งสุดท้าย เนื่องจากเป็นการดีกว่าที่จะกำหนดจำนวนลูปสูงสุดเพียงครั้งเดียวสิ่งนี้สามารถทำได้โดยการนอนที่จุดเริ่มต้นของลูปถ้าi > 1
:
for i in $(seq 1 5); do [ $i -gt 1 ] && sleep 15; command && s=0 && break || s=$?; done; (exit $s)
for i in 1 2 3 4 5
ด้วยfor i in {1..5}
เพราะง่ายต่อการบำรุงรักษา
command
ล้มเหลว
[[ i -eq 5]]
เป็นเงื่อนไขหรือก่อนนอนเพื่อหลีกเลี่ยงปัญหานี้
function fail {
echo $1 >&2
exit 1
}
function retry {
local n=1
local max=5
local delay=15
while true; do
"$@" && break || {
if [[ $n -lt $max ]]; then
((n++))
echo "Command failed. Attempt $n/$max:"
sleep $delay;
else
fail "The command has failed after $n attempts."
fi
}
done
}
ตัวอย่าง:
retry ping invalidserver
สร้างผลลัพธ์นี้:
ping: unknown host invalidserver
Command failed. Attempt 2/5:
ping: unknown host invalidserver
Command failed. Attempt 3/5:
ping: unknown host invalidserver
Command failed. Attempt 4/5:
ping: unknown host invalidserver
Command failed. Attempt 5/5:
ping: unknown host invalidserver
The command 'ping invalidserver' failed after 5 attempts
สำหรับโลกแห่งความเป็นจริงตัวอย่างการทำงานกับคำสั่งที่ซับซ้อนดูสคริปต์นี้
นี่คือฟังก์ชันสำหรับลองใหม่
function retry()
{
local n=0
local try=$1
local cmd="${@: 2}"
[[ $# -le 1 ]] && {
echo "Usage $0 <retry_number> <Command>"; }
until [[ $n -ge $try ]]
do
$cmd && break || {
echo "Command Fail.."
((n++))
echo "retry $n ::"
sleep 1;
}
done
}
retry $*
ผลผลิต:
[test@Nagios ~]$ ./retry.sh 3 ping -c1 localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.207 ms
--- localhost ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.207/0.207/0.207/0.000 ms
[test@Nagios ~]$ ./retry.sh 3 ping -c1 localhostlasjflasd
ping: unknown host localhostlasjflasd
Command Fail..
retry 1 ::
ping: unknown host localhostlasjflasd
Command Fail..
retry 2 ::
ping: unknown host localhostlasjflasd
Command Fail..
retry 3 ::
bash retry.sh 3 ping -c1 localhost
GNU Parallel มี--retries
:
parallel --retries 5 --delay 15s ::: ./do_thing.sh
นี่คือนามแฝง / สคริปต์หนึ่งบรรทัดที่ฉันโปรดปราน
alias retry='while [ $? -ne 0 ] ; do fc -s ; done'
จากนั้นคุณสามารถทำสิ่งต่าง ๆ เช่น:
$ ps -ef | grep "Next Process"
$ retry
และมันจะยังคงรันคำสั่งก่อนหน้าจนกว่าจะพบ "กระบวนการถัดไป"
fc -e "#"
fc -s
ฉันใช้สคริปต์นี้ที่ทำให้ลองใหม่ของคำสั่งที่กำหนดประโยชน์ของสคริปต์นี้คือถ้าล้มเหลวในการลองใหม่ทั้งหมดมันจะเก็บรหัสทางออก
#!/usr/bin/env bash
if [ $# -ne 3 ]; then
echo 'usage: retry <num retries> <wait retry secs> "<command>"'
exit 1
fi
retries=$1
wait_retry=$2
command=$3
for i in `seq 1 $retries`; do
echo "$command"
$command
ret_value=$?
[ $ret_value -eq 0 ] && break
echo "> failed with $ret_value, waiting to retry..."
sleep $wait_retry
done
exit $ret_value
อาจจะง่ายขึ้น
ดูตัวอย่างด้านล่าง:
n=0
while :
do
nc -vzw1 localhost 3859
[[ $? = 0 ]] && break || ((n++))
(( n >= 5 )) && break
done
ฉันกำลังพยายามเชื่อมต่อพอร์ต 3389 บน localhost มันจะลองอีกครั้งจนกว่าจะล้มเหลว 5 ครั้งถ้าสำเร็จก็จะทำให้เกิดการวนซ้ำ
$?
มันมีอยู่สถานะของคำสั่งถ้ามันหมายถึงหมายถึงคำสั่งประสบความสำเร็จในการทำงานถ้าอื่น ๆ กว่าศูนย์หมายถึงคำสั่ง fai
ดูเหมือนซับซ้อนเล็กน้อยอาจเป็นคนที่ทำได้ดีกว่านี้
$?
มันมีอยู่สถานะของคำสั่งถ้ามันหมายถึงหมายถึงคำสั่งประสบความสำเร็จในการทำงานถ้าอื่น ๆ กว่าศูนย์หมายถึงคำสั่งล้มเหลว
คุณสามารถใช้loop
คำสั่งได้ที่นี่เช่น:
$ loop './do_thing.sh' --every 15s --until-success --num 5
ซึ่งจะทำสิ่งที่คุณทำทุก ๆ 15 วินาทีจนกว่ามันจะประสบความสำเร็จสูงสุดห้าครั้ง
นี่คือretry
ฟังก์ชั่นวนซ้ำสำหรับนักเขียนโปรแกรมที่ใช้งานได้:
retry() {
cmd=$1
try=${2:-15} # 15 by default
sleep_time=${3:-3} # 3 seconds by default
# Show help if a command to retry is not specified.
[ -z "$1" ] && echo 'Usage: retry cmd [try=15 sleep_time=3]' && return 1
# The unsuccessful recursion termination condition (if no retries left)
[ $try -lt 1 ] && echo 'All retries failed.' && return 1
# The successful recursion termination condition (if the function succeeded)
$cmd && return 0
echo "Execution of '$cmd' failed."
# Inform that all is not lost if at least one more retry is available.
# $attempts include current try, so tries left is $attempts-1.
if [ $((try-1)) -gt 0 ]; then
echo "There are still $((try-1)) retrie(s) left."
echo "Waiting for $sleep_time seconds..." && sleep $sleep_time
fi
# Recurse
retry $cmd $((try-1)) $sleep_time
}
ส่งคำสั่ง (หรือชื่อฟังก์ชัน) และจำนวนครั้งในการลองใหม่และระยะเวลาการพักระหว่างการลองใหม่ดังนี้:
retry some_command_or_fn 5 15 # 5 tries, sleep 15 seconds between each
break
ถ้าคำสั่งสำเร็จแล้วมันจะหยุดลูป