Gereksiz gecikme olmadan bash komutunu zaman aşımı


283

Komut satırı komutuna verilen bu yanıt , belirli bir süre sonra bir komutu otomatik olarak öldürmek

bash komut satırından uzun süren bir komutun zaman aşımına uğraması için 1 satırlık bir yöntem önerir:

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

Ancak, belirli bir "uzun süren" komutun zaman aşımından önce bitmesi mümkündür. (Buna "tipik olarak uzun süren ama bazen hızlı" bir komut veya eğlence için tlrbsf diyelim .)

Bu şık 1 katlı yaklaşımın birkaç sorunu var. Birincisi, sleepkoşullu değildir, böylece dizinin bitmesi için geçen süre için istenmeyen bir alt sınır belirler. Tlrbsf komutu 2 saniyede bittiğinde uyku için 30s veya 2m hatta 5m düşünün - çok istenmeyen. İkincisi, killkoşulsuzdur, bu nedenle bu dizi çalışmayan bir süreci öldürmeye ve bu konuda sızlanmaya çalışacaktır.

Yani...

Genellikle uzun çalışan ama bazen hızlı ( "tlrbsf" ) komutunu zaman aşımına uğratmanın bir yolu var mı

  • bir bash uygulaması var (diğer soru zaten Perl ve C cevaplarına sahip)
  • ikisinin başında sona erecek : tlrbsf programın sonlandırılması veya geçen zaman aşımı
  • mevcut olmayan / çalışmayan süreçleri öldürmeyecek (veya isteğe bağlı olarak: kötü bir öldürmeden şikayet etmeyecek )
  • 1 astar olmak zorunda değil
  • Cygwin veya Linux altında çalışabilir

... ve bonus puanlar için, tlrbsf komutunu ön planda ve arka planda herhangi bir 'uyku' veya ekstra işlemi çalıştırır, böylece tlrbsf komutunun stdin / stdout / stderr'i , sanki eskisi gibi yönlendirilebilir doğrudan koşmak?

Öyleyse, lütfen kodunuzu paylaşın. Değilse, lütfen nedenini açıklayın.

Bir süredir yukarıda bahsi geçen örneği hacklemek için harcadım ama bash becerilerimin sınırına ulaşıyorum.


5
Başka bir benzer soru: stackoverflow.com/questions/526782/… (ancak buradaki 'timeout3' cevabının çok daha iyi olduğunu düşünüyorum).
sistem DURAKLAT

2
GNU timeoutyardımcı programını kullanmamak için herhangi bir neden var mı?
Chris Johnson

timeoutHarika! birden fazla komutla bile kullanabilirsiniz (çok satırlı komut dosyası): stackoverflow.com/a/61888916/658497
Noam Manos

Yanıtlar:


149

Bence bu tam olarak istediğin şey:

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 "$@"

Bu arka plan kısmı için $$ kullanarak keskin bir numara. Ve hemen asılı bir tlrbsf öldürecek güzel. Ama ugh, bir yoklama aralığı seçmelisin. Eğer oylamayı çok düşük ayarlarsanız, sabit sinyal ile CPU'yu yiyecektir, tlrbsf'nin daha da uzun süre çalışmasını sağlar!
sistem DURAKLAT

7
Yoklama aralığını seçmek zorunda değilsiniz, varsayılan 1s var, bu oldukça iyi. Ve kontrol çok ucuz, ek yük ihmal edilebilir. Bunun tlrbsf'yi belirgin şekilde daha uzun süre çalıştıracağından şüpheliyim. Uyku 30 ile test ettim ve kullanmama ve kullanmama arasında 0.000 ms fark aldım.
Juliano

6
Tamam, şimdi görüyorum. Anket aralığını == zaman aşımı olarak ayarlarsanız tam gereksinimlerimi karşılar. Ayrıca boru hatlarında çalışır, arka plandaki her şeyle çalışır, birden çok örnekle çalışır ve çalışan diğer işler. Tatlı, teşekkürler!
sistem DURAKLATMA

Bir sinyal göndermek alt kabuğu öldürür, bu yüzden bir satırdaki tüm kill komutlarını astarlamanın onları koruyacağını düşündüm. Ayrıca beklenmedik hataları görüntülemek için stderr çıktısını etkinleştirdim. stackoverflow.com/questions/687948/…
eel ghEEz

1
@Juliano Zaman aşımlarını halletmenin harika bir yolu, çok kullanışlı. Ben zaman aşımı sonra süreç öldürüldüğünde script dönüş çıkış kodu 143 sahip bir yolu var mı acaba? Kill komutundan hemen sonra "çıkış 143" eklemeyi denedim, ama her zaman arayan kodunda çıkış kodu 0 alıyorum.
Salman A. Kagzi

528

Muhtemelen timeoutcoreutils komutunu arıyorsunuz . Coreutils'in bir parçası olduğundan, teknik olarak bir C çözümüdür, ancak yine de coreutils. info timeoutdaha fazla ayrıntı için. İşte bir örnek:

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

21
Mac'te bunu Macports veya homebrew aracılığıyla yükleyebilirsiniz.
Ivan Z. Siu

23
Homebrew üzerinden OS X üzerine yüklendiğinde komut şöyle olurgtimeout
ethicalhack3r

5
... 2003'ten önce coreutils içeren hangi işletim sistemini kullanıyorsunuz?
Keith

5
@Keith: CentOS 5.10, örneğin :-(
sonraki duyuruya kadar duraklatıldı.

9
Açıklığa kavuşturmak için, OSX / mac üzerinde ihtiyacınız olan homebrew komutudur brew install coreutilsve daha sonra kullanabilirsiniz gtimeout.
Ohad Schneider

37

Bu çözüm, bash monitör modundan bağımsız olarak çalışır. Komutunuzu sonlandırmak için uygun sinyali kullanabilirsiniz

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

Gözcü, belirli bir zaman aşımından sonra komutunuzu öldürür; senaryo yavaş görevi bekler ve izleyiciyi sonlandırır. Bunu not etwaitFarklı bir kabuğun alt öğesi olan işlemlerle çalışmadığını .

Örnekler:

  • komutunuz 2 saniyeden fazla çalışıyor ve sonlandırıldı

Komutunuz kesildi

( 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
  • komutunuz zaman aşımından önce bitti (20 saniye)

Komutunuz bitti

( 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
waitbeklediği işlemin çıkış durumunu döndürür. Komutunuz ayrılan süre içinde ancak sıfır olmayan bir çıkış durumuyla çıkarsa, buradaki mantık zaman aşımına uğradığı gibi davranacaktır, yani yazdırın your_command interrupted. Bunun yerine olabilir yapmak waitbir olmadan ifve edip etmediğini kontrol $watcherpid hala o yaparsa sen aşımı yapmadığını biliyorum, var.
George Hawkins

Bunun killbir durumda neden diğerinde kullandığını anlayamıyorum pkill. pkillBu işi doğru yapmak için her ikisini de kullanmam gerekiyordu . Bir komutu içine ()alırsanız, pkillonu öldürmek için kullanmanız gerekir. Ancak, içinde sadece tek bir komut varsa, belki de farklı çalışır ().
nobar

Tanrı sizi korusun efendim :)
Darko Miletic

22

İşte böyle:

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

Eğer değişebilir SIGINTve 10istediğiniz gibi;)


3
"timeout" (en azından) Redhat, Centos, Suse ve Ubuntu üzerindeki coreutils paketinin bir parçasıdır , bu yüzden yoksa yüklemeniz gerekir.
Akom

gerçekten yararlı !!!!!! Neden yingted'in "zaman aşımı 5 / path / to / slow / command with options" bazen çalışmadığını biliyor musunuz?
Decula

Ne yazık ki bu coreutilsFreeBSD paketinde değil .
Paul Bissex

18

Bunu tamamen bash 4.3ve üstü ile yapabilirsiniz :

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

  • Bash 4.3 İhtiyacı Var wait -n

  • Komut öldürüldüyse 137 verir, aksi takdirde komutun dönüş değeri.
  • Boru işleri. (Burada ön plana çıkmanıza gerek yok!)
  • Dahili kabuk komutları veya işlevleriyle de çalışır.
  • Bir alt kabukta çalışır, bu nedenle geçerli kabukta hiçbir değişken dışa aktarma, üzgünüm.

Dönüş koduna ihtiyacınız yoksa, bu daha da basitleştirilebilir:

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

Notlar:

  • Belirtmek gerekir gerekmez konuşan ;içinde ; )ancak daha tutarlı şey yapar ; }-Örnek. Ve set +bmuhtemelen de bırakılabilir, ama üzgünümden daha güvenli.

  • Dışında --forground(muhtemelen) tüm varyant timeoutdesteklerini uygulayabilirsiniz . --preserve-statusgerçi biraz zor. Bu okuyucu için bir egzersiz olarak bırakılır;)

Bu tarif kabukta "doğal olarak" kullanılabilir (olduğu kadar doğal flock fd):

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

Ancak, yukarıda açıklandığı gibi, çevre değişkenlerini çevreleyen kabuğa bu şekilde doğal olarak yeniden aktaramazsınız.

Düzenle:

Gerçek dünya örneği: __git_ps1Çok uzun sürmesi durumunda zaman aşımı (yavaş SSHFS Bağlantıları gibi şeyler için):

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

Edit2: Bugfix. Bunun exit 137gerekli olmadığını ve_timeout olmadığını ve aynı zamanda güvenilmez .

Edit3: git çok zor, bu yüzden tatmin edici bir şekilde çalışmak için bir çift hile gerekiyor.

Edit4: Gerçek dünya GIT örneği _için ilk olarak unuttum _timeout.


1
4 kaya bas. Hepsi bu.
sistem DURAKLAT

1
Bu aslında Bash 4.3 veya daha yenisini gerektirir. cc. The 'wait' builtin has a new '-n' option to wait for the next child to change status. Gönderen: tiswww.case.edu/php/chet/bash/NEWS
Ben Reser

17

En azından debian'da bir paketi olan "timelimit" i tercih ederim.

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

Bu, coreutils "timeout" dan biraz daha güzel çünkü işlemi öldürürken bir şeyler yazdırıyor ve ayrıca bir süre sonra varsayılan olarak SIGKILL gönderiyor.


Oldukça iyi çalışmıyor: / $ zaman timelimit -T2 uyku 10 gerçek 0m10.003s kullanıcı 0m0.000s sys 0m0.000s
hithwen

3
-T2 yerine -t2 kullanın. Büyük -T, SIGTERM göndermeden SIGKILL göndermeye kadar geçen süredir.
maxy

1
Timelimit 1.8'in çatalla iyi çalıştığını ( timelimit -t1 ./a_forking_progiki işlemden sadece birini öldürdüğünü) değil, zaman aşımının işe yaradığını da eklemek isterim .
Jeremy Cochoy

İşlemi öldürürken zaman aşımının bir şeyler yazdırmasını istiyorsanız, "-v" bayrağını kullanın.

10

slowcommand1 saniye sonra zaman aşımına uğramak için :

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

Komutun kendi nedenleriyle zaman aşımına uğradığını veya başarısız olup olmadığını belirlemek için durum kodunun 124 olup olmadığını kontrol edin:

# 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

Çıkış durumu 124 olduğunda, timeoutkomutunuz nedeniyle zaman aşımına uğradı mı yoksa kendi kendine ait bazı iç zaman aşımı mantığı nedeniyle komutun kendisinin sonlandırılıp sonlandırılmayacağını ve 124'ün geri döndüğünü bilmediğinizi unutmayın. yine de, bir tür zaman aşımı oldu.



8

Biraz hacky, ama işe yarıyor. Başka ön plan süreçleriniz varsa çalışmaz (lütfen bunu düzeltmeme yardım edin!)

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

Aslında, 'bonus' kriterlerinizi karşılayarak tersine çevirebileceğinizi düşünüyorum:

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

(ls -ltR / cygdrive / c / windows & SPID = $ {!}; (uyku 1s; $ {SPID} öldür) & CPID = $ {!}; fg 1; $ {CPID} öldür)> fdsa
sistem DURAKLAT

bash: fg: iş kontrolü yok
sistem DURAKLAT

@system PAUSE, set -m, sanırım.
Mart'ta strager

Oturum açma kabuğunda iş kontrolü (set -m) var. Bu, $ içindeki himBH içeriğindeki 'm', ancak alt kabuklar için kaybolmuş gibi görünüyor. Muhtemelen bir Cygwin eseri. grumble
sistem PAUSE

Komut dosyalarında "fg" kullanmayın. "Yardım beklemesini" okuyun.
lhunath

8

zaman aşımı muhtemelen denenecek ilk yaklaşımdır. Zaman aşımına uğradığında yürütmek için bildirime veya başka bir komuta ihtiyacınız olabilir. Biraz arama ve deneme yaptıktan sonra, bu bash betiği ile geldim :

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

Kod netliği ile basit komut dosyası. Şuraya kaydet /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

Çok uzun süre çalışan bir komutun zaman aşımına uğraması:

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

Tamamlanan bir komut için hemen sona erer:

$ run 10 sleep 2
$

3

programZaman aşımından sonra sonlanacak programın adını zaten varsayalım (varsayalım ) (örnek 3saniye olarak), basit ve biraz kirli bir alternatif çözüme katkıda bulunabilirim:

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

Karşılaştırma süreçlerini sistem çağrılarıyla çağırırsam bu mükemmel çalışır.


2
Bu, adı kullanan diğer işlemleri öldürür ve adını değiştirirse işlemi verilen adla öldürmez (örneğin argv[0], daha fazla yer açmak için belki de diğer hack'lere yazarak ).
Jed

Docker kaplarını belirli bir süre sonra durdurmaya çalışırken bunun kullanışlı bir varyasyonunu buldum. Docker istemcisi TERM / INT / KILL'i ön planda çalıştırılan kapsayıcıyı gerçekten durduracak şekilde kabul etmedi. Böylece konteynere bir isim vermek ve kullanmak (sleep 3 && docker stop <container>) &güzel çalıştı. Teşekkürler!
Mat Schaffer

evet kir ve sınırlıdır, ancak şu şekilde geliştirilebilir: { sleep 5 && kill -9 $(ps -fe | grep "program" | grep $$ | tr -s " " | cut -d" " -f2); } & SLEEPPID=$!; bash -c "program" && kill -9 $SLEEPPID"Bu şekilde, sadece mevcut kabuktaki işleri öldürür.
ton

2

Orada da cratimeout(Unix ve Linux sistemleri için C ile yazılmış) Martin Cracauer tarafından.

# 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'

"Özellikle, sinyal davranışını korur." Bu seçeneğe sahip olmak güzel!
sistem DURAKLAT

1

OS X henüz bash 4 kullanmıyor, ne de / usr / bin / timeout içermiyor, bu nedenle / usr / bin / timeout'a benzeyen ev yapımı veya macport olmadan OS X üzerinde çalışan bir işlev Cevap). Parametre doğrulama, yardım, kullanım ve diğer sinyaller için destek okuyucu için bir alıştırmadır.

# 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

Vakaların% 99'unda cevap herhangi bir zaman aşımı mantığı uygulamak DEĞİLDİR. Zaman aşımı mantığı hemen hemen her durumda başka bir şeyin yanlış olduğunu ve bunun yerine düzeltilmesi gerektiğini gösteren kırmızı bir uyarı işaretidir. .

İşleminiz bazen n saniye sonra askıda mı yoksa kopuyor mu? Sonra nedenini öğrenin ve bunun yerine düzeltin.

Bir kenara, strager çözümünü doğru yapmak için, fg 1 yerine wait "$ SPID" kullanmanız gerekir, çünkü komut dosyalarında iş kontrolünüz yoktur (ve açmaya çalışmak aptalca). Dahası, fg 1 senaryoda daha önce başka bir işe başlamadığınız gerçeğine dayanır ki bu da kötü bir varsayımdır.


4
Kaynağın% 100'üne (ve ağ anahtarları gibi donanımın çoğuna) erişim ile, muhtemelen bir zaman aşımından daha iyi çözümler olduğunu kabul ediyorum. Ancak, bir 'tlrbsf' kapalı kaynak olduğunda, sadece ikili olduğunda, bazen bu sınırlamanın üstesinden gelmeniz gerekir.
sistem DURAKLAT

@lhunath, "komut dosyalarında iş denetiminiz yok (ve açmaya çalışmak aptalca)" - Lütfen burada açıklığa kavuşun: stackoverflow.com/questions/690266/…
sistem DURAKLAT

@system PAUSE: Yanıt stackoverflow.com/questions/690266/… doğru, ben de yorumladı.
lhunath

29
lhunath, söylediklerinin bir anlamı yok. zaman aşımının iyi bir seçenek olduğu tonlarca durum vardır, örneğin her zaman ağ üzerinden gitmeniz gerekir.
Nate Murray

Bir istisna: zaten çalışan bir yazılımda zaman aşımı sorunu olup olmadığını kontrol etmek için test komut dosyaları yazıyorsunuz .
peterh - Monica'yı geri yükle

0

Kabuk içeriğini korumak ve zaman aşımlarına izin vermek için bir sorunla karşılaştım, bununla ilgili tek sorun, zaman aşımı sırasında komut dosyasının yürütülmesini durduracak - ama sunulduğum gereksinimlerle iyi:

#!/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

çıkışları ile:

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

tabii ki bir 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 Maalesef, süreç sonlandırma hattını neden değiştirdiğimi ve bunun neden paylaşmak için önemli olduğunu düşündüğümü unuttum. Çok kötü bunu yazmadım. Belki de kill -s TERM başarısını kontrol etmeden önce duraklatmam gerektiğini fark ettim. Yemek kitabındaki 2008 yılı senaryosu, SIGTERM'i gönderdikten hemen sonra sürecin durumunu kontrol ediyor gibi görünüyor ve muhtemelen SIGKILL'i ölen bir işleme göndermeye çalışırken bir hataya yol açıyor.
eel ghEEz

0

Benim sorunum belki biraz farklıydı: Uzak bir makinede ssh ile bir komut başlatıyorum ve komut kilitlenirse kabuk ve childs öldürmek istiyorum.

Şimdi aşağıdakileri kullanıyorum:

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

Bu şekilde başarı durumunda komutun bir zaman aşımı veya dönüş kodu olduğunda komut 255 değerini döndürür

Bir ssh oturumundaki öldürme işlemlerinin etkileşimli bir kabuktan farklı bir şekilde işlendiğini lütfen unutmayın. Ancak, sahte bir terminal ayırmak için ssh için -t seçeneğini de kullanabilirsiniz, bu nedenle etkileşimli bir kabuk gibi davranır


0

İşte bir çocuk süreç yumurtlama dayanmayan bir sürümü - Ben bu işlevselliği gömülü bağımsız bir komut dosyası gerekiyordu. Ayrıca kesirli bir anket aralığı yapar, böylece daha hızlı anket yapabilirsiniz. zaman aşımı tercih edilirdi - ama eski bir sunucuda kaldım

# 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

Çok basit bir yol:

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

ile pkill (opsiyon -f ) Eğer argümanlarla özel komutu öldürmek veya eski sürecini öldürmek önlemek için -n belirtebilirsiniz.


Bunun esas olarak OP'nin görevinde ne olduğunu ve istemediğini gösterdiğini anlıyorsunuz, değil mi? Çünkü her zaman tam uyku gecikmesini bekler.
Etan Reisner

-1

@ Loup'un cevabı üzerine inşa ...

Bir işlemi zaman aşımına uğratmak ve kill job / pid çıktısını susturmak istiyorsanız, şunu çalıştırın:

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

Bu, arka plandaki işlemi alt kabuğa koyar, böylece iş çıktısını görmezsiniz.


-3

Ben bir php betiği çağıran bir cron iş var ve bazı durumlarda, php betiği takılıp. Bu çözüm benim için mükemmeldi.

Kullanırım:

scripttimeout -t 60 /script.php

1
Nedir scripttimeout?
rudolfbyker
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.