จะแนะนำการหมดเวลาใช้งานของสคริปต์เชลล์ได้อย่างไร


35

ฉันต้องการรันเชลล์สคริปต์ที่มีลูปในนั้นและสามารถไปได้ตลอดซึ่งฉันไม่ต้องการที่จะเกิดขึ้น ดังนั้นฉันต้องแนะนำการหยุดพักชั่วคราวสำหรับสคริปต์ทั้งหมด

ฉันจะแนะนำการหมดเวลาสำหรับเชลล์สคริปต์ทั้งหมดภายใต้ SuSE ได้อย่างไร


4
นี่เป็นคำถามที่คลุมเครือมาก คุณช่วยอธิบายเกี่ยวกับการหมดเวลาแบบไหนได้บ้าง? คุณต้องการหมดเวลาในสคริปต์ทั้งหมดหรือหมดเวลาในฟังก์ชั่นหรือคำสั่งเดียว? คุณพยายามจะทำอะไร?
ทิมเคนเนดี้

@ TimKennedy: หวังว่าจะดีขึ้นแล้ว
Radek

1
โปรดดูไทม์เอาท์ในเชลล์สคริปต์ (ฉันไม่คิดว่ามันซ้ำซ้อนเพราะข้อกำหนดในการพกพาของฉันซึ่งไม่รวมเครื่องมือเช่นtimeoutหรือexpect)
Gilles 'ดังนั้น - หยุดความชั่วร้าย'

คำตอบ:


30

หาก GNU timeoutไม่พร้อมใช้งานคุณสามารถใช้expect(Mac OS X, BSD, ... โดยปกติจะไม่มีเครื่องมือและอรรถประโยชน์ของ GNU ตามค่าเริ่มต้น)

################################################################################
# Executes command with a timeout
# Params:
#   $1 timeout in seconds
#   $2 command
# Returns 1 if timed out 0 otherwise
timeout() {

    time=$1

    # start the command in a subshell to avoid problem with pipes
    # (spawn accepts one command)
    command="/bin/sh -c \"$2\""

    expect -c "set echo \"-noecho\"; set timeout $time; spawn -noecho $command; expect timeout { exit 1 } eof { exit 0 }"    

    if [ $? = 1 ] ; then
        echo "Timeout after ${time} seconds"
    fi

}

แก้ไข ตัวอย่าง:

timeout 10 "ls ${HOME}"

ดูดี. ฉันจะดูผลลัพธ์ของคำสั่งที่ดำเนินการบนหน้าจอได้อย่างไร
Radek

สวัสดีเอาต์พุตควรมองเห็นได้เนื่องจาก stdout ไม่ได้ถูกเปลี่ยนทิศทางที่ใด ๆ ฉันเพิ่มตัวอย่างสำหรับการใช้งาน ในกรณีของฉันมันพิมพ์เนื้อหาของ dir บ้านของฉันตามที่คาดไว้ คำสั่งใดไม่พิมพ์ผลลัพธ์ใด ๆ
Matteo

ฉันไม่ได้เรียกมันอย่างถูกต้อง มันใช้งานได้ดีมาก! ขอขอบคุณ. เพียง แต่มันจะไม่ส่งออกจำนวนวินาทีหลังจากหมดเวลา
Radek

@Radek ขออภัยแก้ไข
Matteo

1
ฉันต้องการเน้นว่าหากใช้การหมดเวลาของ GNU สถานะการส่งคืนของtimeoutตัวเองคือ 124 ในกรณีที่หมดเวลาไม่เช่นนั้นจะเป็นสถานะการส่งคืนคำสั่ง
QuasarDonkey

15

ขอบคุณสำหรับการชี้แจง

วิธีที่ง่ายที่สุดในการบรรลุสิ่งที่คุณต้องการคือการเรียกใช้สคริปต์ของคุณด้วยการวนซ้ำภายใน wrapper เช่นtimeoutคำสั่งจากแพ็คเกจ GNU Coreutils

root@coraid-sp:~# timeout --help            
Usage: timeout [OPTION] DURATION COMMAND [ARG]...
   or: timeout [OPTION]
Start COMMAND, and kill it if still running after DURATION.

Mandatory arguments to long options are mandatory for short options too.
  -k, --kill-after=DURATION
                   also send a KILL signal if COMMAND is still running
                   this long after the initial signal was sent.
  -s, --signal=SIGNAL
                   specify the signal to be sent on timeout.
                   SIGNAL may be a name like 'HUP' or a number.
                   See `kill -l` for a list of signals
      --help     display this help and exit
      --version  output version information and exit

DURATION is an integer with an optional suffix:
`s' for seconds(the default), `m' for minutes, `h' for hours or `d' for days.

If the command times out, then exit with status 124.  Otherwise, exit
with the status of COMMAND.  If no signal is specified, send the TERM
signal upon timeout.  The TERM signal kills any process that does not
block or catch that signal.  For other processes, it may be necessary to
use the KILL (9) signal, since this signal cannot be caught.

Report timeout bugs to bug-coreutils@gnu.org
GNU coreutils home page: <http://www.gnu.org/software/coreutils/>
General help using GNU software: <http://www.gnu.org/gethelp/>
For complete documentation, run: info coreutils 'timeout invocation'

ในท้ายที่สุดมันจะง่ายกว่าการเขียนฟังก์ชั่นไทม์เอาต์ของคุณเองซึ่งเชลล์มักจะไม่มีบิวด์อิน


ฉันไม่ทราบว่าติดตั้งสิ่งนี้ทันทีเพราะมันถูกเรียกใช้gtimeoutในการตั้งค่า (OSX)
Joshua Goldberg

7

เรียกใช้กระบวนการจ้องจับผิดจากภายในสคริปต์ของคุณเพื่อฆ่าผู้ปกครองถ้ามันใช้เวลานานเกินไป ตัวอย่าง:

# watchdog process
mainpid=$$
(sleep 5; kill $mainpid) &
watchdogpid=$!

# rest of script
while :
do
   ...stuff...
done
kill $watchdogpid

สคริปต์นี้จะถูกยกเลิกโดยสุนัขเฝ้าบ้านหลังจากห้าวินาที


6
แต่คุณจะต้องรอให้หมดเวลาทุกครั้ง ในตัวอย่างของคุณสคริปต์ของคุณจะทำงาน 5 วินาทีแม้ว่าสคริปต์จะสั้นกว่ามาก คุณควรเก็บ PID ของสุนัขเฝ้าบ้านและฆ่ามันในตอนท้าย
Matteo

@Matteo ยุติธรรมพอ ที่เพิ่ม
Kyle Jones

1
โปรดทราบว่ามันอาจซับซ้อนกว่านั้นขึ้นอยู่กับว่า ... สิ่ง ... กำลังทำอะไร ดูการจับเวลาในเชลล์สคริปต์
Gilles 'หยุดความชั่วร้าย'

อ่านเพิ่มเติม: PID สามารถพิจารณาเป็นระยะเวลานานเท่าไรได้อย่างไรstackoverflow.com/questions/11323410/linux-pid-recycling
Florian Castellane

3

นอกจากนี้ยังมีcratimeoutMartin Cracauer

# cf. http://www.cons.org/cracauer/software.html
# usage: cratimeout timeout_in_msec cmd args
cratimeout 5000 sleep 600
cratimeout 5000 tail -f /dev/null
cratimeout 5000 sh -c 'while sleep 1; do date; done'

2
#!/bin/sh

# Execute a command with a timeout

if [ "$#" -lt "2" ]; then
echo "Usage:   `basename $0` timeout_in_seconds command" >&2
echo "Example: `basename $0` 2 sleep 3 || echo timeout" >&2
exit 1
fi

cleanup()
{
trap - ALRM               #reset handler to default
kill -ALRM $a 2>/dev/null #stop timer subshell if running
kill $! 2>/dev/null &&    #kill last job
  exit 124                #exit with 124 if it was running
}

watchit()
{
trap "cleanup" ALRM
sleep $1& wait
kill -ALRM $$
}

watchit $1& a=$!         #start the timeout
shift                    #first param was timeout for sleep
trap "cleanup" ALRM INT  #cleanup after timeout
"$@"& wait $!; RET=$?    #start the job wait for it and save its return value
kill -ALRM $a            #send ALRM signal to watchit
wait $a                  #wait for watchit to finish cleanup
exit $RET                #return the value

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.