Bunuh program setelah menghasilkan baris yang diberikan, dari skrip shell

15

Latar Belakang:

Saya sedang menulis skrip uji untuk perangkat lunak biologi komputasi. Perangkat lunak yang saya uji dapat membutuhkan waktu berhari-hari atau bahkan berminggu-minggu untuk dijalankan, sehingga memiliki fungsi pemulihan bawaan, dalam kasus sistem crash atau listrik mati.

Saya mencoba mencari cara untuk menguji sistem pemulihan. Secara khusus, saya tidak dapat menemukan cara untuk "crash" program secara terkendali. Saya berpikir entah bagaimana mengatur waktu instruksi SIGKILL untuk dijalankan setelah beberapa waktu. Ini mungkin tidak ideal, karena test case tidak dijamin untuk menjalankan kecepatan yang sama setiap kali (ini berjalan di lingkungan bersama), jadi membandingkan log dengan output yang diinginkan akan sulit.

Perangkat lunak ini TIDAK mencetak garis untuk setiap bagian analisis yang dilengkapinya.

Pertanyaan:

Saya bertanya-tanya apakah ada cara yang baik / elegan (dalam skrip shell) untuk menangkap output dari suatu program dan kemudian membunuh program ketika baris / # garis yang diberikan dihasilkan oleh program?

Paul
sumber
1
Mengapa Anda perlu menghentikan program pada waktu tertentu? Karena buffering output, Anda mungkin akhirnya mematikan program lama setelah itu menghasilkan teks yang Anda periksa.
stardt
@stardt Saya ingin menghentikan program pada waktu tertentu sehingga hasil tes lebih terkontrol dan dapat direproduksi. Saya telah menemukan cara mengatasi ini sekarang. Saya akan mematikan program hanya sekali secara manual, kemudian hanya menguji kode pemulihan. Semua upaya pemulihan akan dimulai dari titik yang sama. Saya sedang menguji bagaimana ia pulih, bukan bagaimana itu crash :)
Paul
1
Kemungkinan duplikat "tonton" output dari suatu perintah sampai string tertentu diamati dan kemudian keluar
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Jawaban:

7

Skrip pembungkus seperti ini adalah pendekatan standar. Script menjalankan program di latar belakang dan kemudian loop, memeriksa file log setiap menit untuk beberapa string. Jika string ditemukan maka program latar belakang dimatikan dan skrip berhenti.

command="prog -foo -whatever"
log="prog.log"
match="this is the what i want to match"

$command > "$log" 2>&1 &
pid=$!

while sleep 60
do
    if fgrep --quiet "$match" "$log"
    then
        kill $pid
        exit 0
    fi
done
Kyle Jones
sumber
14

Jika program Anda akan berhenti pada SIGPIPE (yang merupakan tindakan default) itu harus cukup untuk menyalurkan output ke pembaca yang akan keluar saat membaca baris itu.

Jadi mungkin sesederhana itu

$ program | sed -e '/Suitable text from the line/q'

Jika Anda ingin menekan penggunaan output default

$ program | sed -n -e '/Suitable text from the line/q'

Demikian juga jika seseorang ingin berhenti setelah sejumlah garis tertentu seseorang dapat menggunakan head sebagai ganti sed, misalnya

$ program | head -n$NUMBER_OF_LINES_TO_STOP_AFTER

Waktu yang tepat di mana membunuh terjadi tidak tergantung pada perilaku buffering dari terminal sebagai stardt menunjukkan di komentar.

dmckee --- mantan kucing moderator
sumber
-1. Ada cacat serius di sini. Program hanya akan berhenti ketika (jika) ia mencoba menulis ke pipa (rusak) setelah sedberakhir. OP mengatakan "Perangkat lunak ini TIDAK mencetak garis untuk setiap bagian analisis yang dilengkapinya". Ini mungkin berarti program akan menyelesaikan satu bagian tambahan! Bukti dari konsep: { echo 1; sleep 3; >&2 echo peekaboo; sleep 3; echo 2; } | sed -e '/1/q'. Lihat jawaban ini . Kemungkinan solusi: ( program & ) | sed -e '/Suitable text from the line/q'; killall program. Buat jawaban Anda sadar akan kekurangan dan saya akan mencabut downvote saya.
Kamil Maciorowski
Hmmm ... memang. Dan masalah buffering membuatnya tidak dapat diandalkan bahkan dengan peningkatan Anda (meskipun, tentu saja, itu mempengaruhi setiap solusi yang saya lihat di sini). Saya suka memanfaatkan infrastruktur sinyal bila memungkinkan, tetapi pada titik tertentu mulai kehilangan keanggunannya. Mungkin lebih baik menghapus semuanya.
dmckee --- ex-moderator kitten
7

Sebagai alternatif dari jawaban dmckee, grepperintah dengan -mopsi (lihat misalnya halaman manual ini ) juga dapat digunakan:

compbio | grep -m 1 "Text to match"

untuk berhenti ketika 1 baris yang cocok dengan teks ditemukan atau

compbio | grep -v -m 10 "Text to match"

untuk menunggu 10 baris yang tidak cocok dengan teks yang diberikan.

stardt
sumber
3

Anda dapat menggunakan expect(1)untuk menonton stdout program kemudian menjalankan tindakan yang telah ditentukan pada beberapa pola.

#!/usr/bin/env expect

spawn your-program -foo -bar 
expect "I want this text" { close }

Atau satu baris untuk menyematkan skrip lain:

expect -c "spawn your-program -foo -bar; expect \"I want this text\" { close }"

Perhatikan bahwa expectperintah tidak datang dengan setiap OS secara default. Anda mungkin perlu menginstalnya.

Jamesits
sumber
Ini solusi yang bagus. Saya sarankan menyebutkan set timeout -1untuk menetapkan batas waktu tidak terbatas, jika tidak semuanya akan ditutup di bawah expectbatas waktu 10s default.
pepper_chico
1

Anda bisa menggunakan pernyataan "sementara":

Anda perlu menyalurkan output dari perangkat lunak Anda (atau log-nya) dan kemudian, untuk setiap baris baru, buat tes kondisional, kemudian jalankan kill -KILL. Sebagai contoh (Saya menguji dengan / var / log / messages sebagai file log):

tail -f /var/log/messages | while read line; do test "$line" = "THE LINE YOU WANT TO MATCH" && kill PIDTOKILL; done

Atau dengan perangkat lunak secara langsung:

./biosoftware | while read line; do test "$line" = "THE LINE YOU WANT TO MATCH" && kill PIDTOKILL; done

Anda perlu mengubah jalur log / nama aplikasi, baris yang cocok dan PID untuk dibunuh (Anda juga dapat menggunakan killall).

Semoga berhasil dengan perangkat lunak Anda,

Hugo,

pistache
sumber