Bir kabuk betiğinden belirli bir satır çıktıktan sonra programı öldür


16

Arka fon:

Hesaplamalı biyoloji yazılımı için bir test senaryosu yazıyorum. Test ettiğim yazılımın çalışması günler hatta haftalar alabilir, bu nedenle sistem çökmeleri veya elektrik kesintileri durumunda yerleşik bir kurtarma işlevine sahiptir.

Kurtarma sistemini nasıl test edeceğimizi anlamaya çalışıyorum. Özellikle, programı kontrollü bir şekilde "kilitlemek" için bir yol bulamıyorum. Bir şekilde bir süre sonra bir SIGKILL komutunun çalışmasını zamanlamayı düşünüyordum. Test durumunun her seferinde aynı hızı çalıştırması garanti edilmediğinden (paylaşılan bir ortamda çalışır) bu muhtemelen ideal değildir, bu nedenle günlükleri istenen çıktıyla karşılaştırmak zor olacaktır.

Bu yazılım tamamladığı her analiz bölümü için bir satır yazdırır.

Soru:

Bir programdan çıktı yakalamak ve daha sonra belirli bir satır / satır program tarafından çıktısı olduğunda programı öldürmek için iyi / zarif bir yol (bir kabuk komut dosyası) olup olmadığını merak ediyordum?


1
Neden belirli bir zamanda programı durdurmanız gerekiyor? Çıktı tamponlaması nedeniyle, kontrol ettiğiniz metnin çıktısını aldıktan sonra programı uzun süre öldürebilirsiniz.
Mart'ta stardt

@stardt Programı belirli bir zamanda durdurmak istedim, böylece test sonuçları daha kontrollü ve tekrarlanabilir hale geldi. Şimdi bunun için bir yol buldum. Programı sadece bir kez manuel olarak öldüreceğim, sonra sadece kurtarma kodunu test edeceğim. Tüm kurtarma girişimleri aynı noktadan başlar. Nasıl iyileştiğini test ediyorum, sonuçta nasıl çöktüğünü değil :)
Paul

Yanıtlar:


7

Bunun gibi bir sarıcı komut dosyası standart bir yaklaşımdır. Komut dosyası, programı arka planda çalıştırır ve daha sonra döngüler, günlük dosyasını bazı dizeler için her dakika kontrol eder. Dize bulunursa, arka plan programı öldürülür ve komut dosyası sonlandırılır.

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

15

Programınız SIGPIPE'de (varsayılan eylemdir) sona erecekse, çıktıyı bu satırı okurken çıkacak bir okuyucuya bağlamak yeterli olacaktır.

Yani bu kadar basit olabilir

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

Varsayılan çıktı kullanımını bastırmak istiyorsanız

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

Aynı şekilde, belirli sayıda satırdan sonra durmak isterse, sed yerine başını kullanabilir;

$ program | head -n$NUMBER_OF_LINES_TO_STOP_AFTER

Öldürmek meydana geldiği kesin zaman etmez stardt olarak terminalin tamponlama davranışına bağlıdır açıklamalarda göstermektedir.


-1. Burada ciddi bir kusur var. Program, yalnızca (kesildiğinde) boruya sedsonlandırıldıktan sonra yazmaya çalıştığında sonlanır. OP "Bu yazılım tamamladığı her analiz bölümü için bir çizgi yazdırıyor" diyor. Bu, programın bir ekstra bölüm daha tamamlayacağı anlamına gelebilir! Kavram ispatı: { echo 1; sleep 3; >&2 echo peekaboo; sleep 3; echo 2; } | sed -e '/1/q'. Bu cevaba bakınız . Olası geçici çözüm: ( program & ) | sed -e '/Suitable text from the line/q'; killall program. Cevabınızı kusurdan haberdar edin ve ben aşağı oyumu iptal edeceğim.
Kamil Maciorowski

Hmmm ... gerçekten. Arabelleğe alma sorunu, iyileştirmenizle bile güvenilir değil (yine de, burada gördüğüm her çözümü etkiler). Mümkün olduğunca sinyal altyapısını kullanmayı seviyorum, ama bir noktada zarafetini kaybetmeye başlıyor. Belki de herşeyi kazımak daha iyidir.
dmckee --- eski moderatör kedi yavrusu

7

Dmckee'nin cevabına alternatif olarak grep, -moption (bkz. Bu man sayfası ) komutuna sahip komut da kullanılabilir:

compbio | grep -m 1 "Text to match"

metinle eşleşen 1 satır bulunduğunda durmak veya

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

verilen metne uymayan 10 satır beklemek.


3

expect(1)Bir programın stdout'unu izlemek ve daha sonra bazı desenler üzerinde önceden tanımlanmış eylemler yürütmek için kullanabilirsiniz .

#!/usr/bin/env expect

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

Veya başka bir senaryoya gömmek için bir astar:

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

O Not expectkomut varsayılan olarak her OS ile gelmiyor. Yüklemeniz gerekebilir.


Bu güzel bir çözüm. set timeout -1Belirsiz bir zaman aşımı ayarlamayı belirtmenizi öneririm , aksi takdirde tüm expectvarsayılan 10s zaman aşımı altında kapanır .
pepper_chico

1

Bir "while" ifadesi kullanabilirsiniz:

Yazılımınızın (veya günlüklerinin) çıkışını oluşturmalı ve sonra her yeni satır için bir koşul testi yapmalı, ardından kill -KILL komutunu çalıştırmalısınız. Örneğin (/ var / log / messages ile günlük dosyası olarak test ettim):

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

Veya doğrudan yazılımla:

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

Günlük yolunu / uygulama adını, eşleşecek satırı ve öldürmek için PID'yi (killall'ı da kullanabilirsiniz) yeniden yerleştirmeniz gerekir.

Yazılımınızda iyi şanslar,

Hugo

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.