अनावश्यक देरी के बिना बैश में टाइमआउट करें


283

यह एक निश्चित समय के बाद एक कमांड को ऑटो-कमांड को कमांड लाइन कमांड का जवाब देता है

बैश कमांड लाइन से लंबे समय तक चलने वाले कमांड को टाइमआउट करने के लिए 1-लाइन विधि का प्रस्ताव करता है:

( /path/to/slow command with options ) & sleep 5 ; kill $!

लेकिन यह संभव है कि दिए गए "लंबे समय से चल रहे" आदेश समय समाप्त होने से पहले समाप्त हो सकते हैं। (आइए इसे "आम तौर पर लंबे समय से चलने वाले-लेकिन-कभी-कभी तेज" आदेश, या मनोरंजन के लिए tlrbsf कहते हैं।)

तो इस निफ्टी 1-लाइनर दृष्टिकोण में कुछ समस्याएं हैं। सबसे पहले, sleepसशर्त नहीं है, ताकि अनुक्रम समाप्त करने के लिए उठाए गए समय पर एक अवांछनीय निचली सीमा निर्धारित हो। नींद के लिए 30 या 2 मी या 5 मी पर भी विचार करें, जब tlrbsf कमांड 2 सेकंड में खत्म होती है - अत्यधिक अवांछनीय। दूसरा, killबिना शर्त है, इसलिए यह अनुक्रम गैर-चलने वाली प्रक्रिया को मारने और इसके बारे में सचेत करने का प्रयास करेगा।

इसलिए...

क्या आम तौर पर लंबे समय से चलने वाले लेकिन कभी-कभी तेज ( "tlrbsf" ) कमांड को टाइमआउट करने का एक तरीका है:

  • एक बैश कार्यान्वयन है (दूसरे प्रश्न में पहले से ही पर्ल और सी उत्तर हैं)
  • दो में से पहले को समाप्त करेगा: tlrbsf प्रोग्राम समाप्ति, या समय समाप्त हो गया
  • गैर-मौजूदा / गैर-चल रही प्रक्रियाओं को नहीं मारेंगे (या वैकल्पिक रूप से: एक बुरी हत्या के बारे में शिकायत नहीं करेंगे )
  • 1-लाइनर होना जरूरी नहीं है
  • Cygwin या Linux के अंतर्गत चला सकते हैं

... और, बोनस अंक के लिए, अग्रभूमि में tlrbsf कमांड चलाता है और पृष्ठभूमि में कोई भी 'नींद' या अतिरिक्त प्रक्रिया, जैसे कि tlrbsf कमांड के स्टड / stdout / stderr को पुनर्निर्देशित किया जा सकता है, जैसे कि यह किया गया था सीधे चला?

यदि हां, तो कृपया अपना कोड साझा करें। अगर नहीं, तो कृपया बताएं क्यों।

मैं थोड़ी देर के लिए aforementioned उदाहरण हैक करने की कोशिश कर रहा हूँ, लेकिन मैं अपने मार कौशल की सीमा मार रहा हूँ।


5
इसी तरह का एक और सवाल: stackoverflow.com/questions/526782/… (लेकिन मुझे लगता है कि यहां 'टाइमआउट 3' का जवाब बहुत बेहतर है)।
सिस्टम PAUSE

2
ग्नू timeoutउपयोगिता का उपयोग नहीं करने का कोई कारण ?
क्रिस जॉनसन

timeoutमहान है! आप कई कमांड (मल्टी-लाइन स्क्रिप्ट) के साथ भी उपयोग कर सकते हैं : stackoverflow.com/a/61888916/658497
Noam Manos

जवाबों:


149

मुझे लगता है कि यह वही है जो आप पूछ रहे हैं:

http://www.bashcookbook.com/bashinfo/source/bash-4.0/examples/scripts/timeout3

#!/bin/bash
#
# The Bash shell script executes a command with a time-out.
# Upon time-out expiration SIGTERM (15) is sent to the process. If the signal
# is blocked, then the subsequent SIGKILL (9) terminates it.
#
# Based on the Bash documentation example.

# Hello Chet,
# please find attached a "little easier"  :-)  to comprehend
# time-out example.  If you find it suitable, feel free to include
# anywhere: the very same logic as in the original examples/scripts, a
# little more transparent implementation to my taste.
#
# Dmitry V Golovashkin <Dmitry.Golovashkin@sas.com>

scriptName="${0##*/}"

declare -i DEFAULT_TIMEOUT=9
declare -i DEFAULT_INTERVAL=1
declare -i DEFAULT_DELAY=1

# Timeout.
declare -i timeout=DEFAULT_TIMEOUT
# Interval between checks if the process is still alive.
declare -i interval=DEFAULT_INTERVAL
# Delay between posting the SIGTERM signal and destroying the process by SIGKILL.
declare -i delay=DEFAULT_DELAY

function printUsage() {
    cat <<EOF

Synopsis
    $scriptName [-t timeout] [-i interval] [-d delay] command
    Execute a command with a time-out.
    Upon time-out expiration SIGTERM (15) is sent to the process. If SIGTERM
    signal is blocked, then the subsequent SIGKILL (9) terminates it.

    -t timeout
        Number of seconds to wait for command completion.
        Default value: $DEFAULT_TIMEOUT seconds.

    -i interval
        Interval between checks if the process is still alive.
        Positive integer, default value: $DEFAULT_INTERVAL seconds.

    -d delay
        Delay between posting the SIGTERM signal and destroying the
        process by SIGKILL. Default value: $DEFAULT_DELAY seconds.

As of today, Bash does not support floating point arithmetic (sleep does),
therefore all delay/time values must be integers.
EOF
}

# Options.
while getopts ":t:i:d:" option; do
    case "$option" in
        t) timeout=$OPTARG ;;
        i) interval=$OPTARG ;;
        d) delay=$OPTARG ;;
        *) printUsage; exit 1 ;;
    esac
done
shift $((OPTIND - 1))

# $# should be at least 1 (the command to execute), however it may be strictly
# greater than 1 if the command itself has options.
if (($# == 0 || interval <= 0)); then
    printUsage
    exit 1
fi

# kill -0 pid   Exit code indicates if a signal may be sent to $pid process.
(
    ((t = timeout))

    while ((t > 0)); do
        sleep $interval
        kill -0 $$ || exit 0
        ((t -= interval))
    done

    # Be nice, post SIGTERM first.
    # The 'exit 0' below will be executed if any preceeding command fails.
    kill -s SIGTERM $$ && kill -0 $$ || exit 0
    sleep $delay
    kill -s SIGKILL $$
) 2> /dev/null &

exec "$@"

यह एक गहरी चाल है, पृष्ठभूमि भाग के लिए $ $ का उपयोग करना। और अच्छा है कि यह एक त्रिशंकु को तुरंत मार देगा। लेकिन उह, आपको एक मतदान अंतराल चुनना होगा। और यदि आप मतदान को बहुत कम सेट करते हैं, तो यह सीपीयू को निरंतर सिग्नलिंग के साथ खाएगा, जिससे tlrbsf अधिक समय तक चलेगा!
सिस्टम PAUSE

7
आपको मतदान अंतराल चुनने की ज़रूरत नहीं है, इसमें 1s का डिफ़ॉल्ट है, यह बहुत अच्छा है। और जाँच बहुत सस्ती है, ओवरहेड नगण्य है। मुझे संदेह है कि tlrbsf को अधिक लंबे समय तक चलाना होगा। मैंने नींद 30 के साथ परीक्षण किया, और इसका उपयोग न करने और उपयोग न करने के बीच 0.000ms का अंतर मिला।
जुलियानो

6
ठीक है, अब मैं देख रहा हूं। और यह मेरी सटीक आवश्यकताओं को पूरा करता है यदि आप मतदान अंतराल == टाइमआउट सेट करते हैं। इसके अलावा, पाइपलाइनों में काम करता है, पूरी पृष्ठभूमि के साथ काम करता है, कई उदाहरणों और अन्य नौकरियों के साथ काम करता है। मीठा, धन्यवाद!
सिस्टम PAUSE 1

एक सिग्नल भेजना उप-शेल को मारता है, इसलिए मैंने सोचा कि एक लाइन पर सभी किल कमांड को लाइन करना उन्हें संरक्षित करेगा। मैंने अनपेक्षित त्रुटियों को प्रदर्शित करने के लिए stderr आउटपुट को भी सक्षम किया। stackoverflow.com/questions/687948/…
eel ghEEz

1
@ जूलियानो टाइमआउट को संभालने का एक शानदार तरीका, बहुत उपयोगी है। मुझे आश्चर्य है कि क्या कोई ऐसा तरीका है जिसमें हम स्क्रिप्ट रिटर्न एग्जिटकोड १४३ कर सकते हैं जब प्रक्रिया टाइमआउट के बाद मार दी जाती है? मैंने "कमांड 143" को मारने की कमांड के ठीक बाद जोड़ने की कोशिश की, लेकिन मुझे हमेशा कॉलर स्क्रिप्ट पर एक्जिट कोड 0 मिलता है।
सलमान ए। कागज़ी

528

आप शायद timeoutकोरुटिल्स में कमांड देख रहे हैं । चूंकि यह कोर्यूटिल्स का एक हिस्सा है, यह तकनीकी रूप से एक सी समाधान है, लेकिन यह अभी भी कोर्यूटिल्स है। info timeoutअधिक जानकारी के लिए। यहाँ एक उदाहरण है:

timeout 5 /path/to/slow/command with options

21
Mac में आप Macports या homebrew के माध्यम से इसे इंस्टॉल कर सकते हैं।
इवान जेड सियू

23
जब OS X पर होमब्रे के माध्यम से स्थापित किया जाता है, तो कमांड बन जाता हैgtimeout
ethicalhack3r

5
... क्या ओएस आप उपयोग कर रहे हैं जो 2003 से पहले के कोर्यूटिल्स हैं?
कीथ

5
@ कीथ: सेंटोस 5.10, उदाहरण के लिए :-(
अगली सूचना तक रोका गया।

9
स्पष्ट करने के लिए, आपको OSX / mac पर होमब्रेव कमांड की आवश्यकता है brew install coreutilsऔर फिर आप इसका उपयोग कर सकते हैं gtimeout
ओहद श्नाइडर

37

यह समाधान बैश मॉनिटर मोड की परवाह किए बिना काम करता है। आप अपने सिग्नल को समाप्त करने के लिए उचित सिग्नल का उपयोग कर सकते हैं

#!/bin/sh
( your_command ) & pid=$!
( sleep $TIMEOUT && kill -HUP $pid ) 2>/dev/null & watcher=$!
wait $pid 2>/dev/null && pkill -HUP -P $watcher

देखने वाला दिए गए समय समाप्त होने के बाद आपके_कमांड को मारता है; स्क्रिप्ट धीमे काम की प्रतीक्षा करती है और देखने वाले को समाप्त कर देती है। ध्यान दें कि waitउन प्रक्रियाओं के साथ काम नहीं करता है जो एक अलग शेल के बच्चे हैं।

उदाहरण:

  • your_command 2 सेकंड से अधिक चलता है और समाप्त कर दिया गया था

your_command बाधित हुआ

( sleep 20 ) & pid=$!
( sleep 2 && kill -HUP $pid ) 2>/dev/null & watcher=$!
if wait $pid 2>/dev/null; then
    echo "your_command finished"
    pkill -HUP -P $watcher
    wait $watcher
else
    echo "your_command interrupted"
fi
  • your_command मध्यांतर से पहले समाप्त हो गया (20 सेकंड)

your_command समाप्त हुआ

( sleep 2 ) & pid=$!
( sleep 20 && kill -HUP $pid ) 2>/dev/null & watcher=$!
if wait $pid 2>/dev/null; then
    echo "your_command finished"
    pkill -HUP -P $watcher
    wait $watcher
else
    echo "your_command interrupted"
fi

1
waitउस प्रक्रिया का निकास स्थिति लौटाता है जिस पर वह प्रतीक्षा करता है। इसलिए यदि आपका कमांड आवंटित समय के भीतर बाहर निकलता है, लेकिन गैर-शून्य निकास स्थिति के साथ तो यहाँ तर्क व्यवहार करेगा जैसे कि यह समय समाप्त हो गया है, अर्थात प्रिंट your_command interrupted। इसके बजाय आप इसके बिना कर सकते हैं और फिर जांचें कि क्या पिड अभी भी मौजूद है, अगर ऐसा होता है तो आपको पता है कि आपने समय समाप्त नहीं किया था। waitif$watcher
जॉर्ज हॉकिन्स

मैं यह पता नहीं लगा सकता कि यह killएक मामले में क्यों इस्तेमाल होता है लेकिन pkillदूसरे में। मुझे pkillइस काम को सही ढंग से करने के लिए दोनों का उपयोग करने की आवश्यकता थी । मुझे उम्मीद है कि यदि आप एक कमांड लपेटते हैं (), तो आपको pkillइसे मारने के लिए उपयोग करने की आवश्यकता होगी । लेकिन शायद यह अलग तरह से काम करता है अगर अंदर एक ही कमांड है ()
नोबार

भगवान आपको आशीर्वाद दें :)
Darko Miletic

22

तुम वहाँ जाओ:

timeout --signal=SIGINT 10 /path/to/slow command with options

आप बदल सकते हैं SIGINTऔर 10के रूप में आप की इच्छा;)


3
"टाइमआउट" रेडहैट, सेंटोस, स्यूस और उबंटू पर (कम से कम) कोरुटिल्स पैकेज का हिस्सा है , इसलिए आपको इसे स्थापित करने की आवश्यकता होगी यदि आपके पास यह नहीं है।
अकोम

यह वास्तव में उपयोगी है !!!!!! क्या आप जानते हैं कि कभी-कभी काम नहीं करने के कारण "टाइमआउट 5 / पाथ / टू / स्लो / कमांड" के लिए क्यों?
डिकुला

दुर्भाग्य से यह coreutilsFreeBSD पर पैकेज में नहीं है ।
पॉल बिसेक्स

18

आप इसे पूरी तरह से bash 4.3और ऊपर के साथ कर सकते हैं :

_timeout() { ( set +b; sleep "$1" & "${@:2}" & wait -n; r=$?; kill -9 `jobs -p`; exit $r; ) }
  • उदाहरण: _timeout 5 longrunning_command args
  • उदाहरण: { _timeout 5 producer || echo KABOOM $?; } | consumer
  • उदाहरण: producer | { _timeout 5 consumer1; consumer2; }
  • उदाहरण: { while date; do sleep .3; done; } | _timeout 5 cat | less

  • के लिए बैश 4.3 चाहिए wait -n

  • यदि आदेश मारा गया था, तो 137 देता है, अन्यथा कमांड का वापसी मूल्य।
  • पाइप के लिए काम करता है। (आपको यहां अग्रभूमि जाने की आवश्यकता नहीं है!)
  • आंतरिक शेल कमांड या फ़ंक्शन के साथ भी काम करता है।
  • एक उप-प्रकार में चलता है, इसलिए वर्तमान शेल में कोई चर निर्यात नहीं होता है, क्षमा करें।

यदि आपको रिटर्न कोड की आवश्यकता नहीं है, तो इसे और भी सरल बनाया जा सकता है:

_timeout() { ( set +b; sleep "$1" & "${@:2}" & wait -n; kill -9 `jobs -p`; ) }

टिप्पणियाँ:

  • कड़ाई से बोलते हुए आपको अंदर की जरूरत नहीं ;है ; ), लेकिन यह बात को और अधिक सुसंगत बनाता है ; }। और set +bशायद दूर भी छोड़ा जा सकता है, लेकिन खेद से बेहतर सुरक्षित है।

  • --forground(शायद) को छोड़कर आप सभी प्रकार के timeoutसमर्थन को लागू कर सकते हैं । --preserve-statusहालांकि थोड़ा मुश्किल है। इसे पाठक के लिए एक अभ्यास के रूप में छोड़ दिया गया है;)

इस नुस्खा का उपयोग शेल में "स्वाभाविक रूप से" (के रूप में प्राकृतिक flock fd) के लिए किया जा सकता है :

(
set +b
sleep 20 &
{
YOUR SHELL CODE HERE
} &
wait -n
kill `jobs -p`
)

हालांकि, जैसा कि ऊपर बताया गया है, आप पर्यावरण चर को इस तरह से स्वाभाविक रूप से संलग्न करने वाले शेल में फिर से निर्यात नहीं कर सकते।

संपादित करें:

वास्तविक विश्व उदाहरण: समय समाप्त होने __git_ps1में बहुत लंबा समय लगता है (धीमे SSHFS- लिंक जैसी चीजों के लिए):

eval "__orig$(declare -f __git_ps1)" && __git_ps1() { ( git() { _timeout 0.3 /usr/bin/git "$@"; }; _timeout 0.3 __orig__git_ps1 "$@"; ) }

एडिट 2: बगफिक्स। मैंने देखा कि exit 137इसकी आवश्यकता नहीं है और _timeoutयह एक ही समय में अविश्वसनीय बनाता है ।

Edit3: gitएक डाई-हार्ड है, इसलिए इसे संतोषजनक तरीके से काम करने के लिए एक डबल-ट्रिक की आवश्यकता है।

Edit4: वास्तविक दुनिया GIT उदाहरण के लिए _पहली बार में भूल गए _timeout


1
बैश 4 चट्टानें। बस इतना ही।
सिस्टम PAUSE

1
इसके लिए वास्तव में बैश 4.3 या नए की आवश्यकता होती है। cc. The 'wait' builtin has a new '-n' option to wait for the next child to change status. प्रेषक: tiswww.case.edu/php/chet/bash/NEWS
बेन

17

मैं "टाइमलीमिट" पसंद करता हूं, जिसमें कम से कम डेबियन में पैकेज है।

http://devel.ringlet.net/sysutils/timelimit/

यह कोर्यूटिल्स "टाइमआउट" की तुलना में थोड़ा अच्छा है क्योंकि यह प्रक्रिया को मारते समय कुछ प्रिंट करता है, और यह डिफ़ॉल्ट रूप से कुछ समय बाद SIGKILL भी भेजता है।


यह बहुत अच्छी तरह से काम करने के लिए प्रतीत नहीं होता है: / $ समय timelimit -T2 नींद 10 असली 0m10.003s उपयोगकर्ता 0m0.000s sys 0m0.000s
hithwen

3
उपयोग -t2 नहीं -T2। बिग -T SIGKILL भेजने से SIGTERM भेजने तक का समय है।
अधिकतम

1
मैं जोड़ना चाहूंगा कि टिमिलिमिट 1.8 कांटा के साथ अच्छी तरह से काम करने के लिए नहीं बैठता है ( timelimit -t1 ./a_forking_progकेवल दो प्रक्रिया में से एक को मार डालो), लेकिन टाइमआउट काम करता है।
जेरेमी कोचॉय

यदि आप प्रक्रिया को मारते समय कुछ प्रिंट करना चाहते हैं, तो बस "-v" ध्वज का उपयोग करें।

10

slowcommand1 सेकंड के बाद टाइमआउट करने के लिए :

timeout 1 slowcommand || echo "I failed, perhaps due to time out"

यह निर्धारित करने के लिए कि क्या समय समाप्त हो गया है या अपने स्वयं के कारणों से विफल हो गया है, जांचें कि क्या स्थिति कोड 124 है:

# ping for 3 seconds, but timeout after only 1 second
timeout 1 ping 8.8.8.8 -w3
EXIT_STATUS=$?
if [ $EXIT_STATUS -eq 124 ]
then
echo 'Process Timed Out!'
else
echo 'Process did not timeout. Something else went wrong.'
fi
exit $EXIT_STATUS

ध्यान दें कि जब बाहर निकलने की स्थिति 124 है, तो आप यह नहीं जानते हैं कि क्या यह आपके timeoutआदेश के कारण समाप्त हो गया है , या क्या यह आदेश अपने स्वयं के कुछ आंतरिक टाइमआउट तर्क के कारण समाप्त हो गया है और फिर 124 वापस आ गया है। आप सुरक्षित रूप से किसी भी मामले में मान सकते हैं , हालांकि, कि किसी तरह का एक समयबाह्य हुआ।


9

Http://www.pixelbeat.org/scripts/timeout स्क्रिप्ट भी देखें , जिसकी कार्यक्षमता को नए कोर्यूटिल्स में एकीकृत किया गया है


नीट, सरल, TERM का उपयोग करता है और KILL का नहीं। अच्छा! मैं इस तरह एक जाल / प्रतीक्षा समाधान तलाश रहा था जब मैंने मूल रूप से सवाल खड़ा किया था।
सिस्टम PAUSE

एक मार के मामले में टाइमआउट १२४ देता है।
13:15

8

Kinda hacky, लेकिन यह काम करता है। यदि आपके पास अन्य अग्रभूमि प्रक्रियाएँ नहीं हैं, तो कृपया इसे ठीक करने में मेरी मदद करें!)

sleep TIMEOUT & SPID=${!}; (YOUR COMMAND HERE; kill ${SPID}) & CPID=${!}; fg 1; kill ${CPID}

वास्तव में, मुझे लगता है कि आप इसे 'बोनस' मानदंडों को पूरा करते हुए उलट सकते हैं:

(YOUR COMMAND HERE & SPID=${!}; (sleep TIMEOUT; kill ${SPID}) & CPID=${!}; fg 1; kill ${CPID}) < asdf > fdsa

(ls -ltR / cygdrive / c / windows और SPID = $ {}; (नींद 1s; मार $ {SPID}) और CPID = $ {!}; fg 1; $ $ {CPID}; fdsa
system PAUSE

bash: fg: कोई जॉब कंट्रोल नहीं
सिस्टम PAUSE

@ सिस्टम PAUSE, सेट-एम, मुझे लगता है।
स्ट्रैजर

मुझे लॉगिन शेल में जॉब कंट्रोल (सेट-एम) है। कि $ की - एचबीएच सामग्री में 'एम' है - लेकिन यह उपश्रेणियों के लिए गायब हो गया है। संभवतः एक साइगविन कलाकृति। बड़बड़ाना
प्रणाली

लिपियों में "fg" का प्रयोग न करें। "सहायता प्रतीक्षा" पढ़ें।
लहनाथ

8

टाइमआउट शायद कोशिश करने वाला पहला तरीका है। यदि यह समय समाप्त होता है, तो आपको अधिसूचना या किसी अन्य कमांड को निष्पादित करने की आवश्यकता हो सकती है। काफी खोज और प्रयोग के बाद, मैं इस बैश स्क्रिप्ट के साथ आया :

if 
    timeout 20s COMMAND_YOU_WANT_TO_EXECUTE;
    timeout 20s AS_MANY_COMMANDS_AS_YOU_WANT;
then
    echo 'OK'; #if you want a positive response
else
    echo 'Not OK';
    AND_ALTERNATIVE_COMMANDS
fi

5

कोड स्पष्टता के साथ सरल स्क्रिप्ट। इसे सहेजें /usr/local/bin/run:

#!/bin/bash

# run
# Run command with timeout $1 seconds.

# Timeout seconds
timeout_seconds="$1"
shift

# PID
pid=$$

# Start timeout
(
  sleep "$timeout_seconds"
  echo "Timed out after $timeout_seconds seconds"
  kill -- -$pid &>/dev/null
) &
timeout_pid=$!

# Run
"$@"

# Stop timeout
kill $timeout_pid &>/dev/null

बहुत समय से चलने वाली एक कमांड देखें:

$ run 2 sleep 10
Timed out after 2 seconds
Terminated
$

पूरा होने वाले कमांड के लिए तुरंत समाप्त होता है:

$ run 10 sleep 2
$

3

यदि आप पहले से ही कार्यक्रम का नाम जानते हैं (मान लेते हैं program) समय समाप्त होने के बाद (उदाहरण के 3सेकंड के रूप में), मैं एक सरल और कुछ हद तक गंदे वैकल्पिक समाधान में योगदान कर सकता हूं:

(sleep 3 && killall program) & ./program

यह पूरी तरह से काम करता है अगर मैं सिस्टम कॉल के साथ बेंचमार्क प्रक्रियाओं को कॉल करता हूं।


2
यह अन्य प्रक्रियाओं को मारता है जो नाम का उपयोग करने के लिए होता है और दिए गए नाम के साथ इस प्रक्रिया को नहीं मारता है अगर यह अपना नाम बदलता है (जैसे कि लिखकर argv[0], शायद अधिक हैक करने के लिए अन्य हैक्स के साथ)।
जेड

मुझे एक निश्चित समय के बाद डॉकटर कंटेनरों को रोकने की कोशिश करते समय इस भिन्नता का पता चला। Docker क्लाइंट TERM / INT / KILL को इस तरह से स्वीकार नहीं करता था, जो वास्तव में उस कंटेनर को रोक देगा जो अग्रभूमि में चलाया जा रहा था। इसलिए कंटेनर को एक नाम देना और (sleep 3 && docker stop <container>) &अच्छी तरह से काम करना। धन्यवाद!
Mat Schaffer

हां यह गंदगी और सीमित है, लेकिन इसे बेहतर बनाया जा सकता है: { sleep 5 && kill -9 $(ps -fe | grep "program" | grep $$ | tr -s " " | cut -d" " -f2); } & SLEEPPID=$!; bash -c "program" && kill -9 $SLEEPPID"इस तरह, यह केवल मौजूदा शेल में नौकरियों को मार देगा।
टन

2

cratimeoutमार्टिन क्रेकर (यूनिक्स और लिनक्स सिस्टम के लिए सी में लिखित) द्वारा भी है।

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

"विशेष रूप से, यह सिग्नल व्यवहार को संरक्षित करता है।" अच्छी बात है कि वह विकल्प है!
सिस्टम PAUSE

1

OS X bash 4 का उपयोग नहीं करता है, न ही इसके पास / usr / bin / timeout है, इसलिए यहाँ एक फ़ंक्शन है जो OS-x पर होम-काढ़ा या macports के बिना काम करता है जो कि / usr / bin / timeout के समान है (Tino के आधार पर) जवाब)। अन्य संकेतों के लिए पैरामीटर सत्यापन, सहायता, उपयोग और समर्थन पाठक के लिए एक अभ्यास है।

# implement /usr/bin/timeout only if it doesn't exist
[ -n "$(type -p timeout 2>&1)" ] || function timeout { (
    set -m +b
    sleep "$1" &
    SPID=${!}
    ("${@:2}"; RETVAL=$?; kill ${SPID}; exit $RETVAL) &
    CPID=${!}
    wait %1
    SLEEPRETVAL=$?
    if [ $SLEEPRETVAL -eq 0 ] && kill ${CPID} >/dev/null 2>&1 ; then
      RETVAL=124
      # When you need to make sure it dies
      #(sleep 1; kill -9 ${CPID} >/dev/null 2>&1)&
      wait %2
    else
      wait %2
      RETVAL=$?
    fi
    return $RETVAL
) }

0

99% मामलों में जवाब किसी भी समय तर्क को लागू करने के लिए नहीं है। टाइमआउट तर्क लगभग किसी भी स्थिति में एक लाल चेतावनी संकेत है कि कुछ और गलत है और इसके बजाय तय किया जाना चाहिए ।

क्या आपकी प्रक्रिया एन सेकंड के बाद कभी-कभी लटकी या टूट रही है? फिर पता करें कि क्यों और इसके बजाय इसे ठीक करें।

एक तरफ के रूप में, स्ट्रैगर के समाधान को सही करने के लिए, आपको एफजी 1 के बजाय "$ एसपीआईडी" का उपयोग करने की आवश्यकता है, क्योंकि स्क्रिप्ट में आपके पास नौकरी नियंत्रण नहीं है (और इसे चालू करने की कोशिश करना बेवकूफी है)। इसके अलावा, एफजी 1 इस तथ्य पर निर्भर करता है कि आपने स्क्रिप्ट में पहले कोई अन्य काम शुरू नहीं किया था जो कि बनाने के लिए एक बुरी धारणा है।


4
स्रोत के 100% (और अधिकांश हार्डवेयर, जैसे नेटवर्क स्विच) तक पहुंच के साथ, मैं इस बात से सहमत हूं कि टाइमआउट की तुलना में शायद बेहतर समाधान हैं। लेकिन जब एक 'tlrbsf' बंद-स्रोत, केवल बाइनरी होता है, तो कभी-कभी आपको उस सीमा के आसपास काम करना पड़ता है।
प्रणाली PAUSE

@ ललनाथ, "स्क्रिप्ट्स में आपके पास जॉब कंट्रोल नहीं है (और इसे चालू करने की कोशिश करना बेवकूफी है)" - कृपया यहाँ स्पष्ट करें: stackoverflow.com/questions/690266/…
सिस्टम PAUSE

@ सिस्टम सिस्टम: जवाब stackoverflow.com/questions/690266/… सही है, मैंने इस पर भी टिप्पणी की।
लूनाथ

29
लूनाथ, जो आप कह रहे हैं उसका कोई मतलब नहीं है। ऐसे कई मामले हैं जहां समय समाप्त होना एक अच्छा विकल्प है, जैसे कि कभी भी आपको नेटवर्क पर जाना होगा।
नैट मरे

एक अपवाद: यदि आप पहले से चल रहे सॉफ़्टवेयर में टाइमआउट की समस्या नहीं है, तो यह जांचने के लिए आप परीक्षण स्क्रिप्ट लिख रहे हैं ।
पीटर - मोनिका

0

मुझे शेल संदर्भ को संरक्षित करने और टाइमआउट की अनुमति देने के लिए एक समस्या के साथ प्रस्तुत किया गया था, इसके साथ एकमात्र समस्या यह है कि टाइमआउट पर स्क्रिप्ट का निष्पादन बंद हो जाएगा - लेकिन यह उन जरूरतों के साथ ठीक है जिन्हें मुझे प्रस्तुत किया गया था:

#!/usr/bin/env bash

safe_kill()
{
  ps aux | grep -v grep | grep $1 >/dev/null && kill ${2:-} $1
}

my_timeout()
{
  typeset _my_timeout _waiter_pid _return
  _my_timeout=$1
  echo "Timeout($_my_timeout) running: $*"
  shift
  (
    trap "return 0" USR1
    sleep $_my_timeout
    echo "Timeout($_my_timeout) reached for: $*"
    safe_kill $$
  ) &
  _waiter_pid=$!
  "$@" || _return=$?
  safe_kill $_waiter_pid -USR1
  echo "Timeout($_my_timeout) ran: $*"
  return ${_return:-0}
}

my_timeout 3 cd scripts
my_timeout 3 pwd
my_timeout 3 true  && echo true || echo false
my_timeout 3 false && echo true || echo false
my_timeout 3 sleep 10
my_timeout 3 pwd

आउटपुट के साथ:

Timeout(3) running: 3 cd scripts
Timeout(3) ran: cd scripts
Timeout(3) running: 3 pwd
/home/mpapis/projects/rvm/rvm/scripts
Timeout(3) ran: pwd
Timeout(3) running: 3 true
Timeout(3) ran: true
true
Timeout(3) running: 3 false
Timeout(3) ran: false
false
Timeout(3) running: 3 sleep 10
Timeout(3) reached for: sleep 10
Terminated

निश्चित रूप से मुझे लगता है कि वहाँ एक dir बुलाया गया था scripts


0
#! /bin/bash
timeout=10
interval=1
delay=3
(
    ((t = timeout)) || :

    while ((t > 0)); do
        echo "$t"
        sleep $interval
        # Check if the process still exists.
        kill -0 $$ 2> /dev/null || exit 0
        ((t -= interval)) || :
    done

    # Be nice, post SIGTERM first.
    { echo SIGTERM to $$ ; kill -s TERM $$ ; sleep $delay ; kill -0 $$ 2> /dev/null && { echo SIGKILL to $$ ; kill -s KILL $$ ; } ; }
) &

exec "$@"

@Tino क्षमा करें मैं भूल गया कि मैंने प्रक्रिया समाप्ति रेखा क्यों बदल दी और मुझे लगा कि इसे साझा करना महत्वपूर्ण क्यों है। बहुत बुरा मैंने यह नहीं लिखा। शायद, मैंने पाया कि मुझे किल-एस ट्रेम की सफलता के लिए जाँच करने से पहले रुकना चाहिए। कुक बुक से वर्ष 2008 की स्क्रिप्ट SIGTERM भेजने के तुरंत बाद प्रक्रिया की स्थिति की जांच करने के लिए लगती है, संभवतः SIGKILL को एक प्रक्रिया में भेजने की कोशिश करने में त्रुटि के कारण हुई।
इल घुइज़

0

मेरी समस्या शायद कुछ अलग थी: मैं एक दूरस्थ मशीन पर ssh के माध्यम से एक कमांड शुरू करता हूं और यदि कमांड हैंग हो जाता है तो शेल और चिल्ड को मारना चाहते हैं।

मैं अब निम्नलिखित का उपयोग करता हूं:

ssh server '( sleep 60 && kill -9 0 ) 2>/dev/null & my_command; RC=$? ; sleep 1 ; pkill -P $! ; exit $RC'

इस तरह से कमांड 255 पर लौटता है जब सफलता के मामले में टाइमआउट या कमांड का रिटर्नकोड होता था

कृपया ध्यान दें कि एक ssh सत्र से हत्या की प्रक्रियाओं को एक इंटरैक्टिव शेल से अलग किया जाता है। लेकिन आप छद्म टर्मिनल को आवंटित करने के लिए s-s विकल्प का भी उपयोग कर सकते हैं, इसलिए यह एक इंटरैक्टिव शेल की तरह कार्य करता है


0

यहां एक संस्करण है जो एक बच्चे की प्रक्रिया को जन्म देने पर निर्भर नहीं करता है - मुझे एक स्टैंडअलोन स्क्रिप्ट की आवश्यकता थी जो इस कार्यक्षमता को एम्बेड करती है। यह एक आंशिक चुनाव अंतराल भी करता है, जिससे आप जल्दी मतदान कर सकते हैं। टाइमआउट पसंद किया गया होगा - लेकिन मैं एक पुराने सर्वर पर अटका हुआ हूं

# wait_on_command <timeout> <poll interval> command
wait_on_command()
{
    local timeout=$1; shift
    local interval=$1; shift
    $* &
    local child=$!

    loops=$(bc <<< "($timeout * (1 / $interval)) + 0.5" | sed 's/\..*//g')
    ((t = loops))
    while ((t > 0)); do
        sleep $interval
        kill -0 $child &>/dev/null || return
        ((t -= 1))
    done

    kill $child &>/dev/null || kill -0 $child &>/dev/null || return
    sleep $interval
    kill -9 $child &>/dev/null
    echo Timed out
}

slow_command()
{
    sleep 2
    echo Completed normally
}

# wait 1 sec in 0.1 sec increments
wait_on_command 1 0.1 slow_command

# or call an external command
wait_on_command 1 0.1 sleep 10

-1

एक बहुत ही सरल तरीका:

# command & sleep 5; pkill -9 -x -f "command"

साथ pkill (विकल्प -f ) आप तर्क के साथ अपने विशिष्ट आदेश को मारने या पुराने प्रक्रिया को मारने से बचने के लिए -n निर्दिष्ट कर सकते हैं।


आपको यह महसूस होता है कि ओपी के पास अपने पद पर क्या है और वह क्या इंगित करता है कि वह नहीं चाहता है, है ना? क्योंकि यह हमेशा पूरी नींद की देरी का इंतजार करता है।
इटन रीसनर

-1

@ लाउप के जवाब पर बिल्डिंग ...

यदि आप किसी प्रक्रिया को टाइमआउट करना चाहते हैं और किल जॉब / पीआईडी ​​आउटपुट को मौन करते हैं, तो रन करें:

( (sleep 1 && killall program 2>/dev/null) &) && program --version 

यह पृष्ठभूमि की प्रक्रिया को एक उपधारा में रखता है ताकि आपको नौकरी आउटपुट न दिखे।


-3

मेरे पास एक क्रॉन जॉब है जो php स्क्रिप्ट को कॉल करता है और, कुछ समय के लिए, यह php स्क्रिप्ट पर अटक जाता है। यह समाधान मेरे लिए एकदम सही था।

मैं उपयोग करता हूं:

scripttimeout -t 60 /script.php

1
क्या है scripttimeout?
रुडोल्फबाइकर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.