Ulangi perintah Unix setiap x detik selamanya

480

Ada built-in perintah Unix repeatyang argumen pertamanya adalah berapa kali untuk mengulangi perintah, di mana perintah (dengan argumen apa pun) ditentukan oleh argumen yang tersisa repeat.

Sebagai contoh,

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

akan menggema string yang diberikan 100 kali dan kemudian berhenti.

Saya ingin perintah serupa - sebut saja forever- yang berfungsi sama kecuali argumen pertama adalah jumlah detik untuk jeda di antara pengulangan, dan itu berulang selamanya. Sebagai contoh,

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

Saya pikir saya akan bertanya apakah hal itu ada sebelum saya menulisnya. Saya tahu ini seperti Perl 2-baris atau skrip Python, tapi mungkin ada cara yang lebih standar untuk melakukan ini. Jika tidak, jangan ragu untuk mengirimkan solusi dalam bahasa scripting favorit Anda, gaya Rosetta Stone .

PS: Mungkin cara yang lebih baik untuk melakukan ini adalah dengan menyamaratakan repeatuntuk mengambil jumlah kali untuk mengulangi (dengan -1 yang berarti tak terhingga) dan jumlah detik untuk tidur di antara pengulangan. Contoh di atas kemudian menjadi:

% repeat 100 0 echo "I will not automate this punishment."
% repeat -1 5 echo "This will get echoed every 5 seconds forever."
Dreeves
sumber
1
Mengapa tidak: ulangi perintah [-t kali] [-n angka] [args ...]?
Jonathan Leffler
17
Keren. Sayangnya baik di Ubuntu saya dan AIX saya ulangi adalah perintah tidak ditemukan . Bisakah Anda melakukan type repeatdan memberi tahu saya dari mana datangnya?
3
Saya juga di Ubuntu dan tidak menginstal ulang. Setiap informasi tentang cara menginstal ini akan sangat membantu.
Rory
7
repeatadalah perintah builtin di csh dan tcsh.
Keith Thompson
2
@KeithThompson, csh, tcsh dan zsh . Meskipun itu lebih kata kunci daripada builtin
Stéphane Chazelas

Jawaban:

615

Coba watchperintahnya.

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

Yang seperti itu:

watch -n1  command

akan menjalankan perintah setiap detik (well, secara teknis, setiap satu detik ditambah waktu yang diperlukan untuk commandmenjalankan sebagai watch(setidaknya procpsdan busyboximplementasi) hanya tidur satu detik di antara dua berjalan command), selamanya.

Apakah Anda ingin meneruskan perintah execalih-alih sh -c, gunakan -xopsi:

watch -n1 -x command

Di macOS, Anda bisa dapatkan watchdari Mac Ports :

port install watch

Atau Anda bisa mendapatkannya dari Homebrew :

brew install watch
Gregor Brandt
sumber
2
Anda dapat menggunakan MacPorts untuk menginstalnya. sudo port install watch
10
Juga tersedia dalam homebrew (brew install watch).
Lyle
28
+1 Untuk alat canggih yang baru. Saya dulu while true; do X; sleep Y; done- Ini jauh lebih baik.
Adam Matan
4
Masalah dengan alat ini (setidaknya di Ubuntu) adalah ia memaksa layar penuh, jadi jika saya membuang beberapa info berkala, saya kehilangan info sebelumnya.
scorpiodawg
4
Disebut cmdwatchpada FreeBSD (dari port:) sysutils/cmdwatch.
Ouki
243

Pesta

while+ sleep:

while true
do 
    echo "Hi"
    sleep 1
done

Berikut hal yang sama dengan tulisan singkat satu kalimat (Dari komentar di bawah):

while sleep 1; do echo "Hi"; done

Menggunakan ;untuk memisahkan perintah dan kegunaan sleep 1untuk whilepengujian karena selalu mengembalikan true. Anda dapat menempatkan lebih banyak perintah dalam loop - cukup pisahkan dengan;

Kesalahan sintaks
sumber
2
Saya percaya itu berfungsi seperti yang ditulis dalam shell Bourne generik, juga.
dmckee
5
@dreeves, menggunakan ";" sebagai pemisah, perintah dapat dieksekusi dalam satu baris. Lihatlah jawaban Toony sebagai contoh
bbaja42
56
sleep 1 selalu mengembalikan true sehingga Anda dapat menggunakannya sebagai kondisi sementara. Bukan hal yang paling mudah dibaca di dunia tetapi benar-benar sah: saat tidur 1; lakukan gema "Hai"; selesai
David Costa
3
@ David Costa: Anda membuat poin yang masuk akal, tetapi sleeptidak selalu kembali benar. Ī̲ menggunakan loop seperti itu (walaupun dengan penundaan lebih lama) yaitu karena ada cara untuk menghentikannya dengan anggun dengan membunuh proses tidur.
Incnis Mrsi
2
@IncnisMrsi Saya tidak memikirkannya, ia benar-benar mengembalikan nol hanya ketika waktu telah berlalu dan tidak-nol ketika diakhiri oleh sinyal. Terima kasih telah menunjukkannya
David Costa
71

Ini hanya versi yang lebih pendek dari while+sleepjawaban lain , jika Anda menjalankan tugas semacam ini sesering rutinitas harian Anda, menggunakan ini akan menyelamatkan Anda dari penekanan tombol yang tidak perlu, dan jika baris perintah Anda mulai memahami lebih lama, yang ini sedikit lebih mudah. Tapi yang ini dimulai dengan tidur dulu.

Ini umumnya berguna jika Anda perlu mengikuti sesuatu yang memiliki output satu baris seperti beban mesin:

while sleep 1; do uptime; done
Bekir Dogan
sumber
Iya. Ini harus didokumentasikan di sebelah UUOC.
Johan
10
Dan jika Anda ingin beroperasi seperti "jam tangan" yang dapat Anda lakukanwhile clear; do date; command;sleep 5; done
Johan
Wow, terima kasih atas while sleepkombinasinya, simpan keystoke!
George Y.
45

Satu masalah yang dimiliki oleh semua jawaban yang diposting sejauh ini adalah bahwa waktu perintah dieksekusi dapat melayang. Misalnya, jika Anda melakukan sleep 10perintah di antara, dan perintah tersebut membutuhkan waktu 2 detik untuk dijalankan, maka perintah itu akan berjalan setiap 12 detik; jika dibutuhkan jumlah variabel waktu untuk dijalankan, maka dalam jangka panjang waktu ketika itu berjalan tidak dapat diprediksi.

Ini mungkin yang Anda inginkan; jika demikian, gunakan salah satu solusi lain, atau gunakan yang ini tetapi sederhanakan sleeppanggilannya.

Untuk resolusi satu menit, tugas cron akan berjalan pada waktu yang ditentukan, terlepas dari berapa lama setiap perintah. (Bahkan pekerjaan cron baru akan diluncurkan bahkan jika yang sebelumnya masih berjalan.)

Berikut ini skrip Perl sederhana yang tertidur hingga interval berikutnya, jadi misalnya dengan interval 10 detik perintah mungkin berjalan pada 12:34:00, 12:34:10, 12:34:20, dll., Bahkan jika Perintah itu sendiri membutuhkan beberapa detik. Jika perintah berjalan lebih dari intervaldetik, interval berikutnya akan dilewati (tidak seperti cron). Interval dihitung relatif terhadap zaman, sehingga interval 86400 detik (1 hari) akan berjalan pada tengah malam UTC.

#!/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?)
}
Keith Thompson
sumber
Lihat juga pertanyaan lain ini
Stéphane Chazelas
1
lebih mudah dalam bash untuk meminimalkan drift (meskipun mungkin melayang di jendela penggunaan yang sangat lama karena perintah sleep dan bash sendiri mengakumulasi waktu eksekusi yang sangat kecil): while :; do sleep 1m & command; wait; done
math
1
@math: Pintar. Ini tidak berfungsi jika Anda memiliki proses latar belakang lain yang berjalan di shell saat ini ( waitakan menunggu semuanya). Itu bisa diperbaiki dengan mengubah waitke wait $!, di mana $!PID sleepproses. Posting ini sebagai jawaban dan saya akan membatalkannya. Tapi itu memang menghasilkan beberapa output luar dalam shell interaktif.
Keith Thompson
29

Saya pikir semua jawaban di sini sejauh ini terlalu berbelit-belit, atau sebaliknya menjawab pertanyaan yang berbeda:

  • + Msgstr "Cara menjalankan program berulang kali sehingga ada penundaan X detik antara saat program selesai, dan selanjutnya dimulai" .

Pertanyaan sebenarnya adalah:

  • "Cara menjalankan program setiap X detik"

Ini adalah dua hal yang sangat berbeda ketika perintah membutuhkan waktu untuk selesai.

Ambil contoh skrip foo.sh(pura-pura ini adalah program yang membutuhkan beberapa detik untuk menyelesaikannya).

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

Anda ingin menjalankan ini setiap detik, dan sebagian besar akan menyarankan watch -n1 ./foo.sh, atau while sleep 1; do ./foo.sh; done. Namun, ini memberikan output:

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

Yang tidak persis dijalankan setiap detik. Bahkan dengan -pflag, seperti yang man watchdisarankan halaman mungkin menyelesaikan ini, hasilnya adalah sama.

Cara mudah untuk menyelesaikan tugas yang diinginkan, yang disentuh oleh beberapa orang, adalah menjalankan perintah di latar belakang. Dengan kata lain:

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

Dan hanya itu yang ada untuk itu.

Anda dapat menjalankannya setiap 500 ms dengan sleep 0.5, atau apa pun.

swalog
sumber
1
Mereka yang memberikan suara pada jawaban yang berbeda, tidak memahami keanggunan jawaban Anda ...
Serge Stroobandt
Ini bagus kecuali program Anda memiliki efek samping. Jika program membutuhkan waktu lebih lama dari interval, efek sampingnya dapat mengganggu (seperti menimpa file). Jika program menunggu sesuatu yang lain, dan sesuatu yang lain berlangsung selamanya, maka Anda memulai lebih banyak pekerjaan latar belakang tanpa batas. Gunakan dengan hati-hati.
John Moeller
4
dapat membalikkan urutan latar belakang untuk memastikan bahwa tidak lebih dari satu ./foo.sh dijalankan pada satu waktu, tetapi tidak lebih cepat dari 1 per detik: while :; do sleep 1 & ./foo.sh; wait; done
matematika
Ya, itu akan melayang, beberapa milidetik pada setiap loop, tetapi itu akan terjadi. Buat date +"%H:%M:%S.%N"foo.sh untuk melihat bagaimana fraksi akan meningkat secara perlahan pada setiap loop.
Isaac
Ya, memang benar bahwa sebagian besar jawaban tidak secara harfiah menjawab pertanyaan itu. Tapi ini taruhan yang hampir aman bahwa mereka menjawab apa yang diinginkan OP. Ini akan menjadi taruhan yang lebih aman jika OP benar-benar menerima jawaban ... Tapi ini bagus, asalkan Anda menyadari kemungkinan efek samping dan Anda yakin bahwa rata-rata jangka waktu perintah tidak akan melebihi waktu siklus
Auspex
17

Di bash:

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

( echodapat diganti dengan perintah apa pun ...

Atau di perl:

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

Di mana print "I will not automate this punishment in absurdum.\n"bisa diganti dengan perintah "any" yang dikelilingi dengan backticks (`).

Dan untuk jeda, tambahkan sleeppernyataan di dalam for loop:

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

dan

perl -e 'for (;1;) {print "I will not automate this punishment in absurdum.\n"; sleep 1}'
Kevin
sumber
16
while [ 0 ]adalah cara yang buruk untuk menulisnya. Artinya 0adalah string dengan panjang> 0. while [ 1 ]atau while [ jeff ]akan melakukan hal yang sama. Lebih baik menulis while true.
Mikel
5
@Mikel: Atauwhile :
Keith Thompson
10

Bash terbaru> = 4.2 di bawah kernel Linux terbaru, berdasarkan jawaban.

Untuk membatasi waktu eksekusi, tidak ada garpu ! Hanya built-in yang digunakan.

Untuk ini, saya menggunakan readfungsi builtin bukan sleep. Sayangnya ini tidak akan berfungsi dengan sesi notty .

Fungsi cepat " repeat" seperti yang diminta:

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
}

Tes kecil dengan string yang dikutip:

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

Bergantung pada rincian dan durasi perintah yang dikirimkan ...

Di bawah kernel Linux baru-baru ini, ada procfile yang /proc/timer_listberisi informasi waktu dalam nanodetik.

Jika Anda ingin menjalankan perintah tepat satu detik, perintah Anda harus berakhir kurang dari satu detik! Dan dari sana, Anda sleephanya perlu sisa detik saat ini.

Jika penundaan lebih penting dan perintah Anda tidak memerlukan waktu yang signifikan, Anda dapat:

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

Tetapi jika tujuan Anda adalah untuk mendapatkan rincian yang lebih baik, Anda harus:

Gunakan informasi nanodetik untuk menunggu hingga awal sedetik ...

Untuk ini, saya menulis fungsi bash kecil:

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

Setelah mengambilnya, Anda dapat:

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

berjalan ${command[@]}langsung di baris perintah, dibandingkan dengan

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

ini harus memberikan hasil yang persis sama.

Rekrut fungsi " repeat" seperti yang diminta:

Anda dapat sumber ini:

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
}

Kemudian cobalah:

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
F. Hauri
sumber
read -tadalah built-in , sedangkan sleeptidak. Ini dapat memiliki efek perbatasan (yaitu memukul [kunci: kembali] mengganggu tidur secara diam-diam ), tetapi ini dapat diobati dengan menguji$foo
F. Hauri
Jawaban yang sangat mengesankan
gena2x
4

Mau coba ini (Bash)?

forever ()   {
    TIMES=shift;
    SLEEP=shift;
    if [ "$TIMES" = "-1" ]; then  
        while true;
        do 
            $@
            sleep $SLEEP
        done
    else
        repeat "$TIMES" $@ 
    fi; }
manatwork
sumber
Saya tidak terlalu bersemangat, jadi perbaikannya disambut baik. Dan sepertinya saya tidak memiliki perintah "repeat" di distro saya.
2
repeatkhusus untuk csh dan tcsh.
Keith Thompson
2
@KeithThompson: and 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); 
}
Dreeves
sumber
4

Bash dan beberapa kerang sejenisnya memiliki (( ... ))notasi yang nyaman di mana ekspresi aritmatika dapat dievaluasi.

Jadi sebagai jawaban untuk tantangan ketiga Anda, di mana penghitungan ulang dan penundaan di antara setiap pengulangan harus dapat dikonfigurasi, berikut adalah salah satu cara untuk melakukannya:

repeat=10
delay=1

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

Jawaban ini juga mengalami penyimpangan waktu yang tercakup dalam jawaban Keith .

Thor
sumber
Ini yang terbaik.
Ahmad Awais
3

Seperti disebutkan oleh gbrandt, jika watchperintah itu tersedia, pasti gunakan itu. Beberapa sistem Unix, bagaimanapun, tidak menginstalnya secara default (setidaknya mereka tidak di tempat saya bekerja).

Inilah solusi lain dengan sintaks dan output yang sedikit berbeda (berfungsi dalam BASH dan SH):

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

Sunting: Saya menghapus beberapa "." dalam pernyataan gema terakhir ... peninggalan dari hari Perl saya;)

Kevin
sumber
3
while [ 1 ]hanya berfungsi karena 1 diperlakukan sebagai string, sama seperti while [ -n 1 ]. while [ 0 ]atau while [ jeff ]akan melakukan hal yang sama. while truejauh lebih masuk akal.
Mikel
3

Jika niat Anda untuk tidak menampilkan pesan ke layar Anda, dan jika Anda mampu mengulangi pekerjaan dalam hitungan menit, crontab , mungkin, akan menjadi alat terbaik Anda. Misalnya, jika Anda ingin menjalankan perintah Anda setiap menit, Anda akan menulis sesuatu seperti ini di crontabfile Anda :

* * * * * my_precious_command

Silakan lihat tutorial untuk contoh lebih lanjut. Anda juga dapat mengatur timing dengan mudah menggunakan Crontab Code Generator .

Barun
sumber
3

Bagaimana jika kita memiliki keduanya?

Inilah idenya: dengan hanya "interval", itu berulang selamanya. Dengan "interval" dan "kali", ini mengulangi jumlah kali ini, dipisahkan oleh "interval".

Penggunaan:

$ loop [interval [times]] command

Jadi, algoritme akan:

  • Daftar barang
  • jika $ 1 hanya mengandung digit, itu adalah interval (default 2)
  • jika $ 2 hanya mengandung digit, itu adalah berapa kali (default infinite)
  • sementara loop dengan parameter ini
    • tidur "interval"
    • jika beberapa kali telah diberikan, kurangi var sampai tercapai

Oleh karena itu:

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
}
Dilarang
sumber
Catatan: itu tidak bekerja dengan mengapung, meskipun sleeptidak menerimanya.
Dilarang
2

Saya akhirnya menciptakan varian pada jawaban swalog. Dengan itu Anda harus menunggu X detik untuk iterasi pertama, saya juga menjalankan latar depan saya jadi ..

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

Cepat, kotor dan mungkin berbahaya untuk boot, tetapi jika Anda petualangan dan tahu apa yang Anda lakukan, menempatkan ini ke dalam repeat.shdan chmod 755itu,

while true
do 
    eval $1 
    sleep $2 
done

Meminta dengan ./repeat.sh <command> <interval>

Perasaan spidey saya mengatakan ini mungkin cara jahat untuk melakukan ini, apakah perasaan spidey saya benar?

mallyone
sumber
8
Eval !? Untuk apa? sleep $1; shift; "$@"atau serupa akan jauh lebih baik.
Mikel
Entah mengapa ini -2. eval mungkin berlebihan ... kecuali ketika Anda membutuhkannya. Eval memungkinkan Anda mendapatkan hal-hal seperti pengalihan ke baris perintah.
Johan
1

Anda dapat menjalankan skrip dari init (menambahkan baris ke / etc / inittab). Script ini harus menjalankan perintah Anda, tidur untuk waktu yang Anda ingin menunggu sampai menjalankan skrip lagi, dan keluar. Init akan memulai skrip Anda lagi setelah keluar.

Roberto Paz
sumber
1

Cara mudah untuk mengulangi pekerjaan dari crontab dengan interval kurang dari satu menit (contoh 20 detik):

crontab: * * * * * script.sh

script.sh:

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

sleep 20
>>retype your commands here.

sleep 20
>>retype your commands here.
Charles nakhel
sumber
1

Anda bisa mendapatkan kekuatan dari juru bahasa python dari shell.

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

ganti lima kapan saja (detik) yang kamu suka.

Perhatian: kembali gunakan SHIFT + ENTER untuk mengembalikan input dalam shell. Dan jangan lupa untuk mengetik 4 spasi SPACE di setiap baris sementara loop.

pah8J
sumber
Perhatikan bahwa python's os.system()mengeksekusi shell untuk menafsirkan baris perintah, sehingga memohon pythonuntuk menjalankan kerang dalam satu lingkaran untuk menjalankan perintah secara periodik adalah sedikit berlebihan. Anda mungkin juga melakukan semua yang ada di shell.
Stéphane Chazelas
Saya setuju denganmu. Namun, ada 5 detik tidur seperti yang Anda gambarkan di setiap loop. Dengan demikian biaya tambahan dari memulai shell baru dapat diabaikan. Jika biaya ini membuat periode lebih lama dari yang diharapkan, Anda dapat mengurangi waktu tidur sebagai persyaratan.
pah8J
0

Solusi ini berfungsi di MacOSX 10.7. Ini bekerja dengan sangat baik.

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

Dalam hal ini

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

atau

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

untuk membersihkan desktop saya terus-menerus.

Dan Ruiz
sumber
1
Apakah Anda bermaksud memiliki sleepperintah di sana?
Keith Thompson
4
while [ 0 ]adalah cara yang aneh untuk menulis infinite loop; ini berfungsi karena testperintah (juga dikenal sebagai [) memperlakukan string yang tidak kosong sebagai benar. while : ; do ... ; donelebih idiomatis, atau jika Anda suka, Anda dapat menggunakan while true ; do ... ; done.
Keith Thompson
0

Anda bisa mendapatkan fungsi rekursif ini:

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

atau tambahkan:

ininterval $*

dan hubungi skrip.

Pengguna tidak diketahui
sumber
0

Untuk berulang kali menjalankan perintah di jendela konsol, saya biasanya menjalankan sesuatu seperti ini:

while true; do (run command here); done

Ini juga berfungsi untuk banyak perintah, misalnya, untuk menampilkan jam yang terus diperbarui di jendela konsol:

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

Thomas Bratt
sumber
Mengapa downvote? Anda dapat melihat ini adalah solusi yang berfungsi dengan menyalin dan menempelkan contoh ke jendela terminal.
Thomas Bratt
Saya pikir Anda turun memilih karena agak berbahaya dan mengkonsumsi CPU.
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
pengguna56318
sumber
0

Dengan zshdan sleepimplementasi yang menerima argumen floating-point:

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

Atau untuk forever:

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

Jika Anda sleeptidak mendukung mengapung, Anda selalu dapat mendefinisikan sebagai pembungkus sekitar zsh's zselectbuiltin:

zmodload zsh/zselect
sleep() zselect -t $((($1 * 100) | 0))
Stéphane Chazelas
sumber
-1

... Saya ingin tahu berapa banyak solusi rumit yang dapat dibuat saat menyelesaikan masalah ini.

Ini bisa sangat mudah ...

open /etc/crontab 

letakkan di sana 1 baris berikutnya ke akhir file seperti:

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

Jika Anda ingin menjalankan sesuatu setiap 1 detik, cukup letakkan di sana:

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

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

dan di dalam file.sh itu harus:

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

your code or commands

dan itu saja!

NIKMATI!

MIrra
sumber
6
Ini tidak benar. * / 60 akan berjalan setiap 60 menit, dan * / 5, misalnya, setiap 5 menit.
mika
1
detik tidak dibolehkan pada crontab
GAD3R
uji barang-barang Anda sebelum menjawab dengan omong kosong yang salah.
Sjas
-1
until ! sleep 60; do echo $(date); command; command; command; done

bekerja untukku.

  1. Saya tidak membutuhkannya setiap 60 detik
  2. "watch" tidak menonton perintah di semua sistem
  3. "watch" hanya dapat mengambil satu perintah (atau file skrip)
  4. menempatkan tidur dalam kondisi alih-alih tubuh membuat loop lebih baik interruptable (jadi klaim dalam menjawab pertanyaan serupa tentang stackoverflow. sayangnya saya dapat menemukannya saat ini)
  5. Saya ingin menjalankannya sekali sebelum penundaan, jadi saya gunakan sampai bukan sementara
Titus
sumber
Saya hanya memperhatikan bahwa "sampai" ternyata mengeksekusi tidur sebelum iterasi pertama juga. apakah ada cara untuk meletakkan kondisi di akhir loop di bash?
Titus