Sonsuza dek her x saniyede bir Unix komutunu tekrarla


480

repeatİlk argümanı, bir komutu tekrarlamanın kaç kez olduğu yerleşik bir Unix komutu vardır , burada komut (herhangi bir argümanla) kalan argümanlar tarafından belirtilir repeat.

Örneğin,

% repeat 100 echo "I will not automate this punishment."

Verilen dizgiyi 100 kere tekrarlar ve sonra durur.

Benzer bir komut istiyorum - hadi söyleyelim - foreverilk argüman tekrarlar arasında duraklatılacak saniye sayısı ve sonsuza dek tekrar eder. Örneğin,

% forever 5 echo "This will get echoed every 5 seconds forever and ever."

Yazmadan önce böyle bir şey olup olmadığını soracağımı düşünmüştüm. 2 satırlık bir Perl veya Python senaryosu gibi olduğunu biliyorum, ama belki bunu yapmanın daha standart bir yolu var. Değilse, en sevdiğiniz kodlama dili olan Rosetta Stone tarzında bir çözüm yollamaktan çekinmeyin .

Not: Belki de bunu yapmanın daha iyi bir yolu, repeattekrar etmek için kaç kez (-1 sonsuzluk anlamına gelir) ve tekrarlar arasında uyumaya gereken saniye sayısını almaktır. Yukarıdaki örnekler şöyle olur:

% repeat 100 0 echo "I will not automate this punishment."
% repeat -1 5 echo "This will get echoed every 5 seconds forever."

1
Neden olmasın: [-t time] [-n number] komutunu tekrarlayın [args ...]?
Jonathan Leffler,

17
Güzel. Maalesef Ubuntu'mda ve AIX tekrarımda , komut bulunamadı . Yapabilir misin type repeatve nereden geldiğini bildirir misin?

3
Ben de Ubuntu'dayım ve tekrarlı yükleme yapmadım. Bunun nasıl kurulacağına dair herhangi bir bilgi yardımcı olacaktır.
Rory

7
repeatcsh ve tcsh dilinde yerleşik bir komuttur.
Keith Thompson

2
@KeithThompson, csh, tcsh ve zsh . Bir yerleşikten daha anahtar kelime olsa da
Stéphane Chazelas

Yanıtlar:


615

watchKomutu dene .

Usage: watch [-dhntv] [--differences[=cumulative]] [--help] [--interval=<n>] 
             [--no-title] [--version] <command>`

Böylece:

watch -n1  command

komutu her saniye çalıştıracak (teknik olarak, her saniye artı artı commandolarak çalışması için geçen süre watch(en azından procpsve busyboxuygulamalar command), sonsuza dek iki saniye arasında bir saniye uyuyor ).

Size komutu geçmek ister miydiniz execyerine sh -c, kullanımı -xseçeneği:

watch -n1 -x command

MacOS üzerinde, alabilirsiniz watchdan Mac Limanları :

port install watch

Ya da Homebrew’ten alabilirsiniz :

brew install watch

2
MacPorts'u yüklemek için kullanabilirsiniz. sudo port yükleme izle

10
Aynı zamanda homebrew de mevcut (demleme takma saati).
Lyle

28
+1 Yeni ve güçlü bir araç için. Alıştım while true; do X; sleep Y; done- Bu daha iyi.
Adam Matan

4
Bu araçla ilgili sorun (en azından Ubuntu'da) tam ekranı zorlamasıdır, bu yüzden bazı periyodik bilgileri bırakıyorsam önceki bilgiyi kaybediyorum.
scorpiodawg

4
cmdwatchFreeBSD'de (portlardan:) çağrılır sysutils/cmdwatch.
Ouki

243

darbe

while+ sleep:

while true
do 
    echo "Hi"
    sleep 1
done

İşte bir shorthand one-liner ile aynı şey (Aşağıdaki yorumlardan):

while sleep 1; do echo "Hi"; done

Kullanımları ;ayrı komutlara ve kullandığı sleep 1için whileher zaman true döndürür beri testi. Döngü içine daha fazla komut koyabilirsiniz - sadece bunları;


2
Ben de genel bir Bourne kabuğundaki gibi çalıştığını düşünüyorum.
dmckee

5
@dreeves, ";" kullanarak ayırıcı olarak komutlar tek bir satırda çalıştırılabilir. Toony'nin cevabına örnek olarak bakın
bbaja42

56
sleep 1 her zaman true değerini döndürür, böylece while koşulunu kullanabilirsiniz. Dünyadaki en okunaklı şey değil ama kesinlikle okunaklı: uyurken 1; echo "Merhaba"; bitti
David Costa

3
@David Costa: Makul bir noktaya değindin, ama her zaman doğru sleepgelmiyor . Longer bu tür döngüler kullanıldı (daha uzun gecikmeyle de olsa), yani uyku sürecinin öldürülmesiyle dikkatlice sonlandırmanın bir yolu var.
Incnis Mrsi

2
@IncnisMrsi Ben düşünmedim, aslında sadece zaman geçtiğinde sıfır ve bir sinyal tarafından sonlandırıldığında sıfır olmayan bir değer döndürür. İşaret ettiğiniz için teşekkürler
David Costa

71

Bu diğer while+sleepcevapların daha kısa bir versiyonudur, bu tür görevleri sık sık günlük rutininiz gibi kullanıyorsanız, bunu kullanmak gereksiz anahtar basmalardan kurtarır ve komut satırınız bunu daha uzun anlamaya başlarsa, bu biraz daha kolaydır. Ama bu ilk önce uyumayla başlar.

Makine yükü gibi tek satırlık bir çıktısı olan bir şeyi izlemeniz gerekirse, bu genellikle kullanışlıdır:

while sleep 1; do uptime; done

Evet. Bu UUOC'nin yanında belgelenmelidir.
Johan

10
Ve eğer "seyretmek" gibi çalışmasını istiyorsan yapabilirsinwhile clear; do date; command;sleep 5; done
Johan

Vay, while sleepkombinasyonu için teşekkürler , keystokes kurtarır!
George Y.,

45

Şu ana kadar gönderilen tüm cevapların bir problemi, komutun yürütüldüğü zamanın kayması olabilir. Örneğin, sleep 10komutlar arasında bir işlem yaparsanız ve komutun çalışması 2 saniye sürerse, her 12 saniyede bir çalışır; eğer değişken bir süre çalıştırmak gerekiyorsa, o zaman uzun vadede çalıştığı zaman tahmin edilemez olabilir.

Bu tam istediğiniz şey olabilir; öyleyse, diğer çözümlerden birini kullanın veya bunu kullanın ancak sleeparamayı basitleştirin .

Bir dakikalık çözünürlük için, her komutun ne kadar sürdüğüne bakılmaksızın, cron işleri belirtilen zamanda çalışacaktır. (Aslında bir öncek hala çalışıyor olsa bile, yeni bir cron işi başlatacak.)

İşte bir sonraki aralığa kadar uyuyan basit bir Perl betiği, yani 10 saniye aralıklarla komut 12:34:00, 12:34:10, 12:34:20, vb. komutun kendisi birkaç saniye sürer. Komut intervalsaniyeden fazla çalışıyorsa , bir sonraki aralık atlanır (cronun aksine). Aralık, çağa göre hesaplanır, bu nedenle UTC'de gece yarısı 86400 saniyelik (1 gün) bir aralık çalışır.

#!/usr/bin/perl

use strict;
use warnings;

if (scalar @ARGV < 2) {
    die "Usage: $0 seconds command [args...]\n";
}

$| = 1;  # Ensure output appears

my($interval, @command) = @ARGV;

# print ">>> interval=$interval command=(@command)\n";

while (1) {
    print "sleep ", $interval - time % $interval, "\n";
    sleep $interval - time % $interval;
    system @command; # TODO: Handle errors (how?)
}


1
sürüklenmeyi en aza indirmek için bash'te daha basittir (uyku komutundan dolayı çok uzun kullanım pencerelerinde sürüklenebilir ve küçük yürütme sürelerini biriktiren bash): while :; do sleep 1m & command; wait; done
matematik

1
@ math: Zeki. Geçerli kabukta çalışan başka arka plan işlemleriniz varsa işe yaramaz wait(hepsini bekler). Yani değiştirerek tamir edilebilir waitiçin wait $!nerede, $!PID olan sleepsüreç. Bunu bir cevap olarak gönder, ben de oyla Ancak etkileşimli bir kabukta bazı yabancı çıktılar üretir.
Keith Thompson

29

Bence şu ana kadarki tüm cevaplar çok sarsılmış ya da bunun yerine farklı bir soruya cevap veriyor:

  • "Bir programın art arda çalıştırılması, böylece program bittiğinde ve bir sonraki başlangıç ​​arasında X saniye gecikmesi olur" .

Asıl soru şuydu:

  • "Her X saniyede bir program nasıl çalıştırılır"

Komutun bitmesi zaman aldığında bunlar iki farklı şeydir.

Örneğin betiği al foo.sh(bunun tamamlanması birkaç saniye süren bir program gibi davran).

#!/bin/bash
# foo.sh
echo `date +"%H:%M:%S"` >> output.txt;
sleep 2.5;
# ---

Bunu her saniye çalıştırmak istiyorsunuz, ve çoğu önermek watch -n1 ./foo.sh, ya da while sleep 1; do ./foo.sh; done. Ancak, bu çıktı verir:

15:21:20
15:21:23
15:21:27
15:21:30
15:21:34

Bu tam olarak her saniye çalıştırılmıyor. -pBayrakla bile , man watchsayfanın bunu çözebileceğini öne sürdüğü gibi , sonuç aynıdır.

Bazı dokunmaların istenen görevi yerine getirmesinin kolay bir yolu, komutu arka planda çalıştırmaktır. Başka bir deyişle:

while sleep 1; do (./foo.sh &) ; done

Ve hepsi bu kadar.

Her 500 ms'de bir sleep 0.5ya da neyin varsa onu çalıştırabilirsin.


1
Farklı cevaplara oy verenler, cevabınızın zerafetini anlamıyorlar ...
Serge Stroobandt

Programınızın yan etkileri olmadığı sürece bu iyidir. Program aralıktan daha uzun sürerse, yan etkiler karışabilir (dosyanın üzerine yazmak gibi). Program başka bir şeyi beklerse ve başka bir şey sonsuza dek sürüyorsa, süresiz olarak daha fazla arka plan işine başlarsınız. Dikkatle kullanın.
John Moeller

4
Bir seferde birden fazla ./foo.sh çalıştırılmadığından, saniyede 1'den daha hızlı olmadığından emin olmak için arka planlamanın sırasını tersine çevirebilir: while :; do sleep 1 & ./foo.sh; wait; done
matematik

Evet, sürüklenecek, her döngüde birkaç milisaniye, ancak olacak. date +"%H:%M:%S.%N"Kesirlerin her bir döngüde yavaşça nasıl arttığını görmek için foo.sh yapın .
Isaac,

Evet, çoğu cevabın kelimenin tam anlamıyla soruyu çözmediği doğrudur . Ancak OP'nin istediğini yanıtlamaları neredeyse güvenli bir bahis. OP aslında bir cevap kabul olsaydı, daha güvenli bir bahis olurdu ... Ama bu, iyi sağlanan olası yan etkilerinin farkında olan ve komuta ortalama çalışma süresi çevrim süresini aşması gitmiyor eminseniz
Auspex

17

İçinde bash:

bash -c 'while [ 0 ]; do echo "I will not automate this punishment in absurdum."; done'

( echoherhangi bir komutla değiştirilebilir ...

Veya perl:

perl -e 'for (;1;) {print "I will not automate this punishment in absurdum.\n"}'

Nerede print "I will not automate this punishment in absurdum.\n"backticks (`) ile çevrili" any "komutu ile değiştirilebilir.

Bir duraklama sleepiçin, for döngüsünün içine bir ifade ekleyin :

bash -c 'while [ 0 ]; do echo "I will not automate this punishment in absurdum."; sleep 1; done'

ve

perl -e 'for (;1;) {print "I will not automate this punishment in absurdum.\n"; sleep 1}'

16
while [ 0 ]bunu yazmak için kötü bir yoldur. Bu 0, uzunluğu> 0 olan bir dize olduğu anlamına gelir while [ 1 ]veya while [ jeff ]aynı şeyi yapar. Yazmak daha iyi while true.
Mikel

5
@Mikel: Orwhile :
Keith Thompson

10

Son bash> = 4.2, son Linux çekirdeği altında, cevaba dayalı.

İdam süresini sınırlamak için çatal yoktur ! Sadece dahili olarak kullanılır.

Bunun için readyerine yerleşik işlevi kullanıyorum sleep. Maalesef, bu dikkat çekici oturumlarla işe yaramaz .

İstenildiği gibi hızlı işlevi " repeat":

repeat () {
   local repeat_times=$1 repeat_delay=$2 repeat_foo repeat_sleep
   read -t .0001 repeat_foo
   if [ $? = 1 ] ;then
       repeat_sleep() { sleep $1 ;}
   else
       repeat_sleep() { read -t $1 repeat_foo; }
   fi
   shift 2
   while ((repeat_times)); do
        ((repeat_times=repeat_times>0?repeat_times-1:repeat_times))
        "${@}"
        ((repeat_times))&& ((10#${repeat_delay//.})) &&
            repeat_sleep $repeat_delay
   done
}

Alıntılanan dizelerle küçük testler:

repeat 3 0 printf "Now: %(%T)T, Hello %s.\n" -1 Guy
Now: 15:13:43, Hello Guy.
Now: 15:13:43, Hello Guy.
Now: 15:13:43, Hello Guy.

repeat -1 .5 printf "Now: %(%T)T, Hello %s.\n" -1 Guy
Now: 15:14:14, Hello Guy.
Now: 15:14:14, Hello Guy.
Now: 15:14:15, Hello Guy.
Now: 15:14:15, Hello Guy.
Now: 15:14:16, Hello Guy.
Now: 15:14:16, Hello Guy.
Now: 15:14:17, Hello Guy.
Now: 15:14:17, Hello Guy.
Now: 15:14:18, Hello Guy.
Now: 15:14:18, Hello Guy.
^C

Tanrısallık ve gönderilen komutun süresine bağlı olarak ...

Son Linux çekirdeği altında /proc/timer_list, nanosaniye cinsinden zaman bilgisi içeren bir procfile var .

Bir komutu tam olarak saniyede bir kez çalıştırmak istiyorsanız, komutunuzun bir saniyeden daha kısa sürede bitmesi gerekir! Ve oradan, sleepsadece geçerli saniyenin geri kalanını yapmak zorundasınız .

Gecikme daha önemliyse ve komutunuz önemli bir zaman gerektirmiyorsa, şunları yapabilirsiniz:

command=(echo 'Hello world.')
delay=10
while :;do
    printf -v now "%(%s)T" -1
    read -t $(( delay-(now%delay) )) foo
    ${command[@]}
  done.

Ancak amacınız daha hassas ayrıntı sağlamaksa, şunları yapmalısınız:

Saniyenin başına kadar beklemek için nanosaniye bilgi kullanın ...

Bunun için küçük bir bash işlevi yazdım:

# bash source file for nano wait-until-next-second

mapfile  </proc/timer_list _timer_list
for ((_i=0;_i<${#_timer_list[@]};_i++));do
    ((_c+=${#_timer_list[_i]}))
    [[ ${_timer_list[_i]} =~ ^now ]] && TIMER_LIST_READ=$_c
    [[ ${_timer_list[_i]} =~ offset:.*[1-9] ]] && \
        TIMER_LIST_OFFSET=${_timer_list[_i]//[a-z.: ]} && \
        break
done
unset _i _timer_list _c
readonly TIMER_LIST_OFFSET TIMER_LIST_READ
waitNextSecondHires() {
    local nsnow nsslp
    read -N$TIMER_LIST_READ nsnow </proc/timer_list
    nsnow=${nsnow%% nsecs*}
    nsnow=$((${nsnow##* }+TIMER_LIST_OFFSET))
    nsslp=$((2000000000-10#${nsnow:${#nsnow}-9}))
    read -t .${nsslp:1} foo
}

Onları temin ettikten sonra şunları yapabilirsiniz:

command=(echo 'Hello world.')
while :;do
    waitNextSecondHires
    ${command[@]}
  done.

${command[@]}karşılaştırmak yerine doğrudan komut satırında çalıştırın

command=(eval "echo 'Hello world.';sleep .3")
while :;do
    waitNextSecondHires
    ${command[@]}
  done.

bu tamamen aynı sonucu vermelidir.

İstenildiği gibi " " işlevini işe alır repeat:

Bunu kaynak olabilir:

mapfile  </proc/timer_list _timer_list
for ((_i=0;_i<${#_timer_list[@]};_i++));do
    ((_c+=${#_timer_list[_i]}))
    [[ ${_timer_list[_i]} =~ ^now ]] && TIMER_LIST_READ=$_c
    [[ ${_timer_list[_i]} =~ offset:.*[1-9] ]] && \
        TIMER_LIST_OFFSET=${_timer_list[_i]//[a-z.: ]} && \
        break
done
unset _i _timer_list _c
readonly TIMER_LIST_OFFSET TIMER_LIST_READ

repeat_hires () {
    local repeat_times=$1 repeat_delay=$2 repeat_foo repeat_sleep repeat_count
    read -t .0001 repeat_foo
    if [ $? = 1 ] ;then
        repeat_sleep() { sleep $1 ;}
    else
        repeat_sleep() { read -t $1 repeat_foo; }
    fi
    shift 2
    printf -v repeat_delay "%.9f" $repeat_delay
    repeat_delay=${repeat_delay//.}
    read -N$TIMER_LIST_READ nsnow </proc/timer_list
    nsnow=${nsnow%% nsec*}
    started=${nsnow##* }
    while ((repeat_times)); do
        ((repeat_times=repeat_times>0?repeat_times-1:repeat_times))
        "${@}"
        ((repeat_times)) && ((10#$repeat_delay)) && {
            read -N$TIMER_LIST_READ nsnow </proc/timer_list
            nsnow=${nsnow%% nsec*}
            nsnow=${nsnow##* }
            (( (nsnow - started) / 10#$repeat_delay - repeat_count++ )) &&
                printf >&2 "WARNING: Command '%s' too long for %f delay.\n" \
                           "${*}" ${repeat_delay:0:${#repeat_delay}-9
                           }.${repeat_delay:${#repeat_delay}-9}
            printf -v sleep "%010d" $((
                10#$repeat_delay - ( ( nsnow - started ) % 10#$repeat_delay ) ))
            repeat_sleep ${sleep:0:${#sleep}-9}.${sleep:${#sleep}-9}
        }
    done
}

O zaman dene:

time repeat_hires 21 .05 sh -c 'date +%s.%N;sleep .01'
1480867565.152022457
1480867565.201249108
1480867565.251333284
1480867565.301224905
1480867565.351236725
1480867565.400930482
1480867565.451207075
1480867565.501212329
1480867565.550927738
1480867565.601199721
1480867565.651500618
1480867565.700889792
1480867565.750963074
1480867565.800987954
1480867565.853671458
1480867565.901232296
1480867565.951171898
1480867566.000917199
1480867566.050942638
1480867566.101171249
1480867566.150913407

real    0m1.013s
user    0m0.000s
sys     0m0.016s

time repeat_hires 3 .05 sh -c 'date +%s.%N;sleep .05'
1480867635.380561067
WARNING: Command 'sh -c date +%s.%N;sleep .05' too long for 0.050000 delay.
1480867635.486503367
WARNING: Command 'sh -c date +%s.%N;sleep .05' too long for 0.050000 delay.
1480867635.582332617

real    0m0.257s
user    0m0.000s
sys     0m0.004s

read -tbir yerleşik iken sleep, değildir. Bunun sınır etkisi olabilir (yani, [tuşa basmak: geri dönüş] uykuyu sessizce keser ), ancak bu testle tedavi edilebilir$foo
F. Hauri

Çok etkileyici cevap
gena2x

4

Bunu denemek ister misin (Bash)?

forever ()   {
    TIMES=shift;
    SLEEP=shift;
    if [ "$TIMES" = "-1" ]; then  
        while true;
        do 
            $@
            sleep $SLEEP
        done
    else
        repeat "$TIMES" $@ 
    fi; }

Kabuklu sıcak değilim, bu yüzden gelişmeler hoş geldiniz. Ve benim dağıtımımda bir "tekrarla" komutu görünmüyor.

2
repeatcsh ve tcsh'a özgüdür.
Keith Thompson

2
@KeithThompson: ve zsh
Thor

4

Perl

#!/usr/bin/env perl
# First argument is number of seconds to sleep between repeats, remaining
# arguments give the command to repeat forever.

$sleep = shift;
$cmd = join(' ', @ARGV);

while(1) {
  system($cmd);
  sleep($sleep); 
}

4

Bash ve bazı kabukları, (( ... ))aritmetik ifadelerin değerlendirilebileceği uygun gösterime sahiptir.

Dolayısıyla, üçüncü tekrarlamanızın cevabı olarak, her tekrar arasında hem tekrar sayısının hem de gecikmenin yapılandırılabilir olması gerektiği, işte bunu yapmanın bir yolu:

repeat=10
delay=1

i=0
while (( i++ < repeat )); do
  echo Repetition $i
  sleep $delay
done

Bu cevap, Keith'in cevabında yer alan zamanlama kaymasından da muzdariptir .


Bu en iyisiydi.
Ahmad Awais,

3

Gbrandt tarafından belirtildiği gibi, eğer watchkomut mevcutsa, kesinlikle kullanın. Ancak bazı Unix sistemleri varsayılan olarak kurulmazlar (en azından çalıştığım yerde değiller).

İşte biraz farklı sözdizimi ve çıktısı olan başka bir çözüm (BASH ve SH'de çalışıyor):

while [ 1 ] ; do
    <cmd>
    sleep <x>
    echo ">>>>>>>>>>>>>" `date` ">>>>>>>>>>>>>>"
done

Düzenleme: Bazı "" kaldırdım. son yankı açıklamasında ... benim Perl günlerimin tutulması;)


3
while [ 1 ]sadece çalışır, çünkü 1 tıpkı bir dize olarak kabul edilir while [ -n 1 ]. while [ 0 ]ya while [ jeff ]da aynı şeyi yapardı. while trueçok daha mantıklı.
Mikel

3

Niyetimiz ekranınıza bir mesaj göstermemekse ve işi dakikalarca tekrarlamayı göze alabiliyorsanız, crontab , belki de en iyi aracınız olur. Örneğin, komutunuzu her dakika yürütmek istiyorsanız, crontabdosyanıza şöyle bir şey yazacaksınız :

* * * * * my_precious_command

Lütfen daha fazla örnek için öğreticiyi inceleyin. Ayrıca, Crontab Code Generator'ü kullanarak zamanlamaları kolayca ayarlayabilirsiniz .


3

Ya ikimizinde olsaydı?

İşte fikir: sadece "aralık" ile sonsuza dek tekrar eder. "Range" ve "times" ile, "range" ile ayrılan bu sayıyı tekrarlar.

Kullanım :

$ loop [interval [times]] command

Yani, algoritma olacak:

  • Liste öğesi
  • $ 1 yalnızca rakam içeriyorsa, aralık (varsayılan 2)
  • $ 2 yalnızca rakam içeriyorsa, sayı kaçtır (varsayılan sonsuz)
  • Bu parametrelerle loop yaparken
    • uyku "aralık"
    • eğer birkaç kez verilirse, erişilinceye kadar var

Bu nedenle:

loop() {
    local i=2 t=1 cond

    [ -z ${1//[0-9]/} ] && i=$1 && shift
    [ -z ${1//[0-9]/} ] && t=$1 && shift && cond=1
    while [ $t -gt 0 ]; do 
        sleep $i
        [ $cond ] && : $[--t]
        $@
    done
}

Not: sleepOnları kabul etmesine rağmen , yüzen ile çalışmaz.
Baroned

2

Swalog'un cevabında bir çeşitleme yaratarak yaralandım. İlk yineleme için X saniye beklemek zorunda kaldım, ben de ön planda koşuyorum.

./foo.sh;while sleep 1; do (./foo.sh) ; done

1

Hızlı kirli ve boot muhtemelen tehlikeli, ama maceracı konum ve ne yaptığınızı biliyorsanız, bu koymak repeat.shve chmod 755bunun,

while true
do 
    eval $1 
    sleep $2 
done

İle çağır ./repeat.sh <command> <interval>

Benim spidey anlayışım bunun muhtemelen bunu yapmanın kötü bir yolu olduğunu söylüyor, benim spidey anlayışım doğru mu?


8
Eval !? Ne için? sleep $1; shift; "$@"veya benzeri çok daha iyi olurdu.
Mikel

Dunno neden bu -2? eval gereğinden fazla olabilir ... ihtiyacın olduğunda hariç. Eval, komut satırına yeniden yönlendirme gibi şeyleri elde etmenizi sağlar.
Johan

1

Bir komut dosyasını init'ten çalıştırabilirsiniz (/ etc / inittab dosyasına bir satır ekleyerek). Bu betiğin komutunu çalıştırması, betiği tekrar çalıştırıncaya kadar beklemek istediğiniz süre boyunca uyuyup çıkması gerekir. Çıktıktan sonra Init betiğinizi tekrar başlatacak.


1

Bir işi bir dakikadan daha kısa bir sürede crontab'dan tekrarlamanın kolay yolu (20 saniye örneği):

crontab: * * * * * script.sh

script.sh:

#!/bin/bash
>>type your commands here.

sleep 20
>>retype your commands here.

sleep 20
>>retype your commands here.

1

Gücü, python yorumlayıcısından kabuğundan alabilirsiniz.

python3 -c "import time, os
while True:
    os.system('your command')
    time.sleep(5)

İstediğiniz zaman (sn) istediğiniz zaman beşi değiştirin.

Dikkat: dönüş, kabuktaki girişi döndürmek için ÜSTKRKT + ENTER tuşlarını kullanın. Ayrıca her satırda 4 SPACE girinti yazmayı unutmayın .


Not pythons' os.system()çok çağırarak, komut satırı yorumlamak için bir kabuk yürüten pythonbir komut periyodik biraz overkill çalıştırmak için bir döngüde kabukları çalıştırın. Kabuğundaki her şeyi yapabilirsin.
Stéphane Chazelas

Size katılıyorum. Ancak, her döngüde açıkladığınız gibi 5 saniyelik bir uyku vardır. Böylece yeni bir kabuk başlatmanın ekstra maliyeti göz ardı edilebilir. Bu maliyet, dönemi beklentiden daha uzun yaparsa, uyku süresini bir gereksinim olarak azaltabilirsiniz.
pah8J

0

Bu çözüm MacOSX 10.7'de çalışır. Harika çalışıyor.

bash -c 'while [ 0 ]; do \
      echo "I will not automate this punishment in absurdum."; done'

Benim durumumda

bash -c 'while [ 0 ]; do ls; done'

veya

bash -c 'while [ 0 ]; do mv "Desktop/* Documents/Cleanup"; done'

masaüstümü sürekli temizlemek için.


1
sleepOrada bir emir vermek mi istediniz ?
Keith Thompson

4
while [ 0 ]sonsuz bir döngü yazmak için garip bir yoldur; test( [boş olarak da bilinir ) komutu boş olmayan bir dizgeyi true olarak kabul ettiğinden çalışır . while : ; do ... ; donedaha deyimsel ya da tercih ederseniz kullanabilirsiniz while true ; do ... ; done.
Keith Thompson

0

Bu özyinelemeli işlevi kaynak olabilir:

#!/bin/bash
ininterval () {
    delay=$1
    shift
    $*
    sleep $delay
    ininterval $delay $*
}

veya bir ekle:

ininterval $*

ve betiği arayın.


0

Bir konsol penceresinde bir komutu tekrar tekrar çalıştırmak için genellikle şöyle bir şey çalıştırırım:

while true; do (run command here); done

Bu, örneğin, sürekli güncellenen bir saati bir konsol penceresinde görüntülemek için, birden çok komut için de geçerlidir:

while true; do clear; date; sleep 1; done


Neden aşağı oy? Bunun çalışan bir çözüm olduğunu, örneği bir terminal penceresine kopyalayıp yapıştırarak görebilirsiniz.
Thomas Bratt

Sanırım reddedildi, çünkü biraz tehlikeli ve işlemciyi tüketiyor.
ojblass

0
#! /bin/sh

# Run all programs in a directory in parallel
# Usage: run-parallel directory delay
# Copyright 2013 by Marc Perkel
# docs at http://wiki.junkemailfilter.com/index.php/How_to_run_a_Linux_script_every_few_seconds_under_cron"
# Free to use with attribution

if [ $# -eq 0 ]
then
   echo
   echo "run-parallel by Marc Perkel"
   echo
   echo "This program is used to run all programs in a directory in parallel" 
   echo "or to rerun them every X seconds for one minute."
   echo "Think of this program as cron with seconds resolution."
   echo
   echo "Usage: run-parallel [directory] [delay]"
   echo
   echo "Examples:"
   echo "   run-parallel /etc/cron.20sec 20"
   echo "   run-parallel 20"
   echo "   # Runs all executable files in /etc/cron.20sec every 20 seconds or 3 times a minute."
   echo 
   echo "If delay parameter is missing it runs everything once and exits."
   echo "If only delay is passed then the directory /etc/cron.[delay]sec is assumed."
   echo
   echo 'if "cronsec" is passed then it runs all of these delays 2 3 4 5 6 10 12 15 20 30'
   echo "resulting in 30 20 15 12 10 6 5 4 3 2 executions per minute." 
   echo
   exit
fi

# If "cronsec" is passed as a parameter then run all the delays in parallel

if [ $1 = cronsec ]
then
   $0 2 &
   $0 3 &
   $0 4 &
   $0 5 &
   $0 6 &
   $0 10 &
   $0 12 &
   $0 15 &
   $0 20 &
   $0 30 &
   exit
fi

# Set the directory to first prameter and delay to second parameter

dir=$1
delay=$2

# If only parameter is 2,3,4,5,6,10,12,15,20,30 then automatically calculate 
# the standard directory name /etc/cron.[delay]sec

if [[ "$1" =~ ^(2|3|4|5|6|10|12|15|20|30)$ ]]
then
   dir="/etc/cron.$1sec"
   delay=$1
fi

# Exit if directory doesn't exist or has no files

if [ ! "$(ls -A $dir/)" ]
then
   exit
fi

# Sleep if both $delay and $counter are set

if [ ! -z $delay ] && [ ! -z $counter ]
then
   sleep $delay
fi

# Set counter to 0 if not set

if [ -z $counter ]
then
   counter=0
fi

# Run all the programs in the directory in parallel
# Use of timeout ensures that the processes are killed if they run too long

for program in $dir/* ; do
   if [ -x $program ] 
   then
      if [ "0$delay" -gt 1 ] 
      then
         timeout $delay $program &> /dev/null &
      else
         $program &> /dev/null &
      fi
   fi
done

# If delay not set then we're done

if [ -z $delay ]
then
   exit
fi

# Add delay to counter

counter=$(( $counter + $delay ))

# If minute is not up - call self recursively

if [ $counter -lt 60 ]
then
   . $0 $dir $delay &
fi

# Otherwise we're done

0

zshVe sleepkayan nokta argümanlarını kabul eden bir uygulama ile :

typeset -F SECONDS=0 n=0
repeat 100 {cmd; sleep $(((n+=3) - SECONDS))}

Veya forever:

for ((;;)) {cmd; sleep $(((n+=3) - SECONDS))}

Eğer senin sleepyüzen desteklemez, her zaman bir sarmalayıcı etrafında olarak yeniden tanımlayabilirsiniz zsh'ın zselectyerleşik:

zmodload zsh/zselect
sleep() zselect -t $((($1 * 100) | 0))

-1

... Bu problemi çözerken ne kadar karmaşık çözümler üretilebileceğini merak ediyorum.

Çok kolay olabilir ...

open /etc/crontab 

Gibi dosyanın sonuna kadar 1 satır ileri koymak:

*/NumberOfSeconds * * * * user /path/to/file.sh

Her 1 saniyede bir şeyler yapmak istiyorsanız, oraya koyun:

*/60 * * * * root /path/to/file.sh 

where that file.sh could be chmod 750 /path/to/file.sh

ve bu dosyanın içinde .sh:

#!/bin/bash 
#What does it do
#What is it runned by

your code or commands

ve hepsi bu!

KEYFİNİ ÇIKARIN!


6
Bu doğru değil. * / 60, her 60 dakikada bir ve * / 5, örneğin, her 5 dakikada bir yayın yapar.
mika

1
saniye cinsinden crontab'a izin verilmiyor
GAD3R

yanlış boka cevap vermeden önce eşyalarını test et.
sjas

-1
until ! sleep 60; do echo $(date); command; command; command; done

benim için çalışıyor.

  1. Tam olarak her 60 saniyede bir ihtiyacım yok
  2. "watch" tüm sistemlerde komut izlemiyor
  3. "watch" yalnızca bir komut alabilir (veya bir komut dosyası)
  4. uykuyu vücut yerine yerine koymak, döngüyü daha iyi kesilebilir kılar (bu yüzden stackoverflow ile ilgili benzer bir sorunun cevabında bir iddia. Maalesef şu anda bulabilirim)
  5. Gecikmeden önce bir kez çalıştırmak istiyorum, bu yüzden yerine

Ben sadece "tekrar" görünüşte ilk yinelemeden önce uyku yürütür fark ettim. koşulu döngünün sonuna bash olarak koymanın bir yolu var mı?
Titus
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.