Setara POSIX untuk batas waktu GNU?

14

Perintah GNU coreutils timeoutsangat berguna untuk situasi scripting tertentu, memungkinkan untuk menggunakan output dari sebuah perintah jika itu cepat dijalankan, dan melewatkannya jika itu akan memakan waktu terlalu lama.

Bagaimana saya bisa memperkirakan perilaku dasar timeoutmenggunakan hanya utilitas yang ditentukan POSIX?


(Aku berpikir itu mungkin melibatkan kombinasi wait, sleep, killdan siapa tahu apa lagi, tapi mungkin aku kehilangan pendekatan yang lebih mudah.)

Wildcard
sumber
3
Lihat Waktu dalam skrip shell , tapi saya tidak menganggap ini duplikat karena saya meminta portabilitas ke sistem pra-POSIX dan saya memiliki persyaratan untuk melestarikan stdin dan stdout yang beberapa solusi yang melibatkan proses latar belakang mengesampingkan.
Gilles 'SO- stop being evil'
command & pid=$! ; sleep 5 && kill $pid
Pandya
1
@ Pandya tidak yang memperkenalkan kondisi balapan sedikit, dimana jika commandselesai dengan cepat ada kemungkinan tipis yang pidakan digunakan kembali oleh proses lain memulai sebelum killperintah dijalankan? Saya tidak ingin itu dalam kode produksi ....
Wildcard
Bisakah Anda menjelaskan lebih lanjut tentang masalah mendasar yang Anda coba selesaikan? Mengapa tidak mengkompilasi timeoutprogram saja dan menggunakannya?
James Youngman
2
@YamesYoungman, saya rasa Anda tidak terlalu terbiasa menulis skrip untuk portabilitas . Meminta cara yang sesuai dengan POSIX (atau yang ditentukan POSIX) untuk melakukan sesuatu menyiratkan bahwa itu dimaksudkan untuk portabel. Mengkompilasi kode sumber ke dalam biner secara tegas tidak portabel, dan, tergantung pada kebijakan keamanan perusahaan Anda, Anda mungkin tidak memiliki kompiler yang diinstal sama sekali pada server produksi.
Wildcard

Jawaban:

2

Pendekatan saya adalah yang ini:

  • Menjalankan perintah sebagai proses latar belakang 1

  • Jalankan "pengawas waktu" sebagai proses latar belakang 2

  • Siapkan pawang untuk menjebak sinyal terminasi di kulit induk

  • Tunggu hingga kedua proses selesai. Proses yang berakhir terlebih dahulu, mengirimkan sinyal terminasi ke induk.

  • Penangan perangkap orang tua membunuh kedua proses latar belakang melalui kontrol pekerjaan (salah satu dari mereka telah diakhiri secara definisi, tetapi pembunuhan itu akan menjadi larangan yang tidak berbahaya karena kita tidak menggunakan PID, lihat di bawah)

Saya mencoba untuk menghindari kemungkinan kondisi ras yang dibahas dalam komentar dengan menggunakan ID kontrol pekerjaan shell (yang akan jelas dalam contoh shell ini) untuk mengidentifikasi proses latar belakang untuk membunuh, bukan PID sistem.

#!/bin/sh

TIMEOUT=$1
COMMAND='sleep 5'

function cleanup {
    echo "SIGTERM trap"
    kill %1 %2
}

trap cleanup SIGTERM

($COMMAND; echo "Command completed"; kill $$) &
(sleep $TIMEOUT; echo "Timeout expired"; kill $$) &

wait
echo "End of execution"

Hasil untuk TIMEOUT=10(perintah berakhir sebelum pengawas):

$ ./timeout.sh 10
Command completed
SIGTERM trap
End of execution

Hasil untuk TIMEOUT=1(watchdog berakhir sebelum perintah):

$ ./timeout.sh 1
Timeout expired
SIGTERM trap
End of execution

Hasil untuk TIMEOUT=5(anjing pengawas dan perintah menghentikan "hampir" secara bersamaan):

./tst.sh 5
Timeout expired
Command completed
SIGTERM trap
End of execution
Guido
sumber
Ini bukan sesuai dengan POSIX karena (a) definisi fungsi seharusnya cleanup() { ...; }dan (b) kontrol pekerjaan adalah fitur bash yang tidak ditentukan oleh POSIX (meskipun ksh dan yang lainnya juga memilikinya). Skrip yang bagus!
Wildcard
Anda juga dapat melakukan lebih baik dengan timeout="$1"; shiftdan (exec "$@"; echo "Command completed"; kill $$)bukannya mengulangi kata-kata daftar argumen.
Wildcard