Lakukan perintah setiap X detik

10

Saya ingin melakukan perintah 10 detik, dan menjalankannya di latar belakang (sehingga menghilangkan watch?). Semua jawaban menunjukkan sesuatu seperti yang berikut ini, tetapi ini akan berlangsung 11 hingga 14 detik. Bagaimana ini bisa dicapai?

while true; do
    # perform command that takes between 1 and 4 seconds
    sleep 10
done
pengguna1032531
sumber
mungkin dengan sinyal real-time. dan penanganan detik kabisat yang tepat. semoga berhasil.
mikeserv
@ mikeserv Jadi, jangan repot-repot mencoba? Saya tidak peduli tentang akurasi mili detik, katakan saja setengah detik.
user1032531
Apa yang ingin Anda capai? Saya menemukan bahwa tugas yang harus dijalankan dengan frekuensi semacam itu biasanya merupakan solusi untuk masalah lain.
Sobrique
@Obrique Persis. Saya sedang melakukan pembuktian konsep logger data polling. Pada kenyataannya, ini akan diprogram dalam bahasa lain, tetapi ini berfungsi untuk saat ini.
user1032531

Jawaban:

16

Bagaimana tentang:

( # In a subshell, for isolation, protecting $!
  while true; do
    perform-command & # in the background
    sleep 10 ;
    ### If you want to wait for a perform-command
    ### that happens to run for more than ten seconds,
    ### uncomment the following line:
    # wait $! ;
    ### If you prefer to kill a perform-command
    ### that happens to run for more than ten seconds,
    ### uncomment the following line instead:
    # kill $! ;
    ### (If you prefer to ignore it, uncomment neither.)
  done
)

ETA: Dengan semua komentar, alternatif, dan subkulit untuk perlindungan ekstra, yang terlihat jauh lebih rumit daripada awalnya. Jadi, sebagai perbandingan, inilah yang terlihat sebelum saya mulai mengkhawatirkan waitatau kill, dengan mereka $!dan kebutuhan akan isolasi:

while true; do perform-command & sleep 10 ; done

Sisanya benar-benar hanya untuk saat Anda membutuhkannya.

Sidhekin
sumber
Bisakah Anda menjelaskan alasan di balik dump kode Anda?
Ismael Miguel
2
Juga, untuk mengutip di mana shell kode Anda bekerja (seperti jawaban mikeserv) sehingga orang tidak bingung ketika shell yang berbeda berperilaku berbeda :)
ash
@ IsmaelMiguel saya pikir komentar akan menjelaskan alasannya. Saya tidak yakin apa yang tidak jelas.
The Sidhekin
1
Manual bash mengatakan tentang $!: "Perluas ID proses pekerjaan yang paling baru ditempatkan di latar belakang," dan bash sleeptidak ditempatkan di latar belakang, jadi tidak, itu tidak akan terjadi. :)
The Sidhekin
1
Wow. salah dalam kedua hal. kapan itu terjadi?
mikeserv
9

Anda dapat melakukan sesuatu seperti berikut di bash, zsh, atau ksh:

SECONDS=0
while   command
do      sleep "$((10-(SECONDS%10)))"
done

Inilah yang dikatakan bashmanual $SECONDS:

$SECONDS

  • Setiap kali parameter ini direferensikan, jumlah detik sejak doa shell dikembalikan. Jika nilai ditugaskan $SECONDS, nilai yang dikembalikan pada referensi berikutnya adalah jumlah detik sejak penugasan ditambah nilai yang diberikan. Jika $SECONDSadalah unset, kehilangan sifat khusus, bahkan jika itu adalah kemudian ulang.

Berikut ini contoh kerjanya:

(   SECONDS=0
    while   sleep   "$((RANDOM%10))"
    do      sleep   "$((10-(SECONDS%10)))"
            echo    "$SECONDS"
    done
)

10
20
30
40
50
60
70
80
90
100
mikeserv
sumber
2
Untuk menghindari pengaturan ulang, SECONDSlakukan sleep "$((10-(($SECONDS-$start_time)%10)))". Anda harus melakukan start_time=$SECONDSsebelum loop.
ctrl-alt-delor
@ Richard - mengapa menghindarinya?
mikeserv
karena suatu hari Anda akan memilikinya dalam skrip yang Anda panggil dari-dalam loop seperti itu. Dan Anda akan menghabiskan sepanjang hari bertanya-tanya mengapa itu tidak berfungsi dengan baik. Singkatnya, itu bukan sarang, jika Anda mengatur ulang SECONDS. Memunculkan sub-shell seperti dalam edit terbaru Anda, juga harus menghindari masalah ini.
ctrl-alt-delor
1
@ Richard - karena pertanyaannya adalah tentang while truepengulangan, saya tidak menemukan kondisi shell yang diharapkan untuk bertahan. Membungkus lingkaran seperti itu dalam konteksnya sendiri biasanya merupakan praktik terbaik. Dalam situasi seperti itu, saya akan lebih peduli untuk melakukannya trapdemi $SECONDSdemi demi, meskipun.
mikeserv
Terima kasih Mike, saya berpikir untuk melakukan sesuatu yang serupa (tetapi belum tahu secara spesifik bagaimana). Tetapi solusi Sidhekin tampaknya melakukan hal yang sama, bukan? Saya tidak memenuhi syarat untuk membuat penilaian atas jawaban yang lebih baik, tetapi merasa berkewajiban untuk memilih sesuatu.
user1032531
3

Hanya BASH - Anda juga dapat menghitung waktu yang dihabiskan oleh perintah Anda dan kurangi dari 10:

TIMEFORMAT=$'%0R'
while true; do
    T=$({ time command; } 2>&1)
    sleep $(( 10-T ))

Dari BASH man:

TIMEFORMAT Nilai parameter ini digunakan sebagai format string yang menentukan bagaimana informasi waktu untuk pipa yang diawali dengan kata waktu dipesan harus ditampilkan. % Karakter memperkenalkan urutan pelarian yang diperluas ke nilai waktu atau informasi lainnya. Urutan melarikan diri dan artinya adalah sebagai berikut; kawat gigi menunjukkan bagian opsional.
%% A% literal.
% [p] [l] R Waktu yang berlalu dalam detik.
% [p] [l] U Jumlah detik CPU yang dihabiskan dalam mode pengguna.
% [p] [l] S Jumlah detik CPU yang dihabiskan dalam mode sistem.
% P Persentase CPU, dihitung sebagai (% U +% S) /% R.

P opsional adalah digit yang menentukan presisi, jumlah digit fraksional setelah titik desimal. Nilai 0 menyebabkan tidak ada titik desimal atau fraksi yang akan dikeluarkan.

Dani_l
sumber