Arka planda çalışan bir kabuk komut dosyasını öldürmek


12

Ben inotifyt araçlarının inotifywait yardımcı programını kullanarak bir dizini izlemek için bir kabuk komut dosyası yazdım. Bu komut dosyasının arka planda sürekli çalışmasını istiyorum, ancak istendiğinde de durdurabilmek istiyorum.

Sürekli çalışmasını sağlamak için while true; bunun gibi:

while true;
do #a set of commands that use the inotifywait utility
end

Bu dosyayı bir dosyaya kaydedip /binçalıştırılabilir yaptım. Arka planda çalışmasını sağlamak nohup <script-name> &için terminali kullandım ve kapattım.

Bu senaryoyu nasıl durduracağımı bilmiyorum. Ben cevaplar baktım burada ve çok yakından ilgili soru burada .

GÜNCELLEME 1: Aşağıdaki @InfectedRoot'un cevabına dayanarak, sorunumu aşağıdaki stratejiyi kullanarak çözebildim. İlk kullanım

ps -aux | grep script_name

ve sudo kill -9 <pid>süreçleri öldürmek için kullanın . Sonra geri döndü kimliği için tekrar pgrep inotifywaitkullanmak zorunda kaldı sudo kill -9 <pid>.

Bu işe yarıyor ama bunun dağınık bir yaklaşım olduğunu düşünüyorum, daha iyi bir cevap arıyorum.

GÜNCELLEME 2: Cevap 2 işlemi öldürmekten ibarettir . Komut satırında komut dosyası çalıştırıldığında, 1 komut dosyasının kendisi ve 2 inotify işlemi başlatıldığından bu önemlidir .



2
Çıkarma -9seçeneğini killve sadece kullanarak killbunun karışıklığı alacak.
Sree

1
Bravo. Tekrar pun nakit kutusuna bazı '$$' almak için, -9seçenek killburada toplam olacağını vurgulamak istiyorum. : P
sözdizimi hatası

Tamlık uğruna: Her iki süreci de aynı anda öldürmek için temiz bir yaklaşım vardır: Süreçleri ayrı ayrı öldürmek yerine, komut dosyasını süreç grubunu aynı anda öldürmek için öldürebilirsiniz. Pgid kabuk komut dosyası ana sürecin pid olarak ve aynı kill: Bir eksi pgid önüne o kill -- -<pgid>, kill -9 -<pgid>vb
cg909

Yanıtlar:


6

killallKomutları geliştirmek, kullanmak ve birleştirmek için:

ps -aux | grep script_name
killall script_name inotifywait

Veya her şeyi tek bir satırda yapın:

killall `ps -aux | grep script_name | grep -v grep | awk '{ print $1 }'` && killall inotifywait

Yukarıdaki çözümünüz çalışıyor, ancak tek satır komutu çalışmıyor. Lütfen kontrol edebilir misiniz? Bir hata alıyorum: işlem yok
light94

@ light94 Error: no process, daha önce öldürdüğünüz anlamına gelmelidir. VLC & Geany gibi diğer iki programı açıp bunun yerine deneyerek test edebilirsiniz .
cremefraiche

Hey @cremefraiche, daha önce kodunuzun çalıştığı gibi .. ama alternatif çözümler arıyordum ve gördüğüm en yaygın çözüm kill <pid> kullanmaktır. Betiğim bu şekilde sona ermediğinden, kodum yanlışsa biraz endişeliyim? Bana rehberlik edebilir misiniz?
light94

İçine grep -v grepçevirerek tasarruf edebilirsiniz . grep script_namegrep -e "[s]cript_name"
nmichaels

3

Kullanarak arka plan işlerini listeleme

# jobs

Sonra önceki iş sayısını seçin ve çalıştırın

misal

# fg 1 

resim açıklamasını buraya girin

ön plana çıkaracak.

Sonra CTRL + C kullanarak öldürün veya kullanarak komut dosyası PID bulmak için daha kolay bir yol

ps -aux | grep script_name

resim açıklamasını buraya girin

Sonra pid kullanarak öldür

sudo kill -9 pid_number_here

2
İlk seçenek benim durumum için geçerli değil çünkü ben komut dosyası belirledikten sonra kabuğu kapatın ve iş komutu sadece aynı kabuk için çalıştığını düşünüyorum. Ayrıca, ikinci seçeneği denedim ve süreci öldürüyor ama pgrep inotifywait yaptığımda, hala orada bir süreç olarak görebilirsiniz.
light94

işler, kabuğu kapatsanız bile işlerin listesini verir. Yine de süreç bitecek orada olacak.
Babin Lonston

2
Denedim ama olmadı.
light94

@ light94 Haklısın. O sık sık burada oldu jobskomut gerçekten sadece yayınlanmaya işler görüntülenen içinde kabuk. Belirli bir terminal penceresini kapattıktan sonra, onlara erişmenin tek yolu ps(bunun için yukarıya bakınız) oldu. Bu yüzden bunu uydurmadığınızdan emin olabilirsiniz.
sözdizimi hatası

2

İşlem adını / pid'ini almak için ps+ grepveya kullanabilirsiniz ; daha sonra / işlem adını veya pid'i öldürmek için kullanın . Tüm aşağıdakiler çalışmalıdır.pgrepkillallpkillkill

killall $(ps aux | grep script_name | grep -v grep | awk '{ print $1 }') && killall inotifywait
(ps -ef | grep script_name | grep -v grep | awk '{ print $1 }' | xargs killall) && killall inotifywait
(ps -ef | grep script_name | grep -v grep | awk '{ print $2 }' | xargs kill) && killall inotifywait
(pgrep -x script_name | xargs kill) && pkill -x inotifywait
pkill -x script_name && pkill -x inotifywait

En önemli şey, sadece öldürmeyi umduğunuz süreci / süreçleri öldürdüğünüzden emin olmanızdır .

pkill/ tam ad yerine pgrepbir kalıpla eşleşir , bu yüzden daha tehlikelidir; tam adı eşleştirmek için buraya eklenir.-x

Ayrıca, kullanırken pgrep/ pkillihtiyacınız olabilir

  • -fKomut satırının tamamını eşleştirmek için (olduğu gibi ps aux)
  • -a işlem adını da yazdırmak için.

Yukarıdakileri uyguladıktan sonra, her birinde bir kullanım hatası alıyorum. ben yapıştırma ve scriptname yerine kopyalama. Çıktı olarak öldürmek için kullanıyorum
light94

Script_name çalışıyor mu? Benim için çalışıyor (debian jessie)
Hongxu Chen

evet çalışıyor. ve çözümünüz yukarıdaki @cremefraiche çözümleriyle neredeyse aynıdır, bu yüzden aynı şekilde çalışmasını bekliyordum: /
light94

Evet, bunu yapmanın olası yollarını bir şekilde özetliyordum, özellikle pgrep/ pkill. Bu hala yanlış pgrepgiderse -x olmadan deneyebilirsiniz . Temel olarak, diğer işlemlerin eşleşip eşleşmediğini kontrol etmeden işlemi bir satır komutunda öldürmenin iyi olduğunu düşünmüyorum.
Hongxu Chen

1

Muhtemelen söyleyebileceğiniz gibi bunu yapmanın birçok yolu vardır.

"GÜNCELLEME # 2" ile ilgili olarak - genel olarak konuşursak, bir üst-alt hiyerarşisindeki herhangi bir işlemi sonlandırmak genellikle ilişkili tüm işlemleri sonlandırır. Ancak bunun birçok istisnası var. İdeal olarak, bir işlem ağacındaki son 'alt' öğeyi sonlandırmak istersiniz, o zaman çalıştırılacak başka görevleri yoksa bu çocuğun ebeveyn (ler) inin çıkması gerekir. Ancak bir ebeveyni öldürürseniz, ebeveyn öldüğünde ve çocukların da çıkması gerektiğinde sinyal çocuklara iletilmelidir - ancak çocuk süreçlerinin sinyali görmezden gelebileceği (tuzaklar veya benzer mekanizmalar yoluyla) ve devam edebileceği durumlar vardır. çalıştırmak için 'init' süreci (veya benzeri) tarafından miras alınacaktır. Ama bu süreç davranışı konusu karmaşıklaşabilir ve ben sadece orada bırakacağım ...

Bir kontrol komut dosyası kullanmak istemiyorsam sevdiğim bir yöntem (daha sonra açıklanacaktır) işlemi başlatmak ve yönetmek için 'ekran' yardımcı programını kullanmaktır. 'Ekran' komutu özelliklerle doludur ve ustalaşması biraz zaman alabilir. Tam bir açıklama için 'ekran' kılavuz sayfasını okumanızı tavsiye ederim. Arka planda bir işlemi başlatmak için hızlı bir örnek komut olacaktır:

ekran -d -m / yol / program / program

Bu, bir 'ekran' oturumunun içinde "/ path / to / program" başlayacaktır.

Koşu oturumunuzu şu komutla görebilirsiniz:

ekran -ls

Ve istediğiniz zaman şu komutla çalışan programınıza yeniden bağlanabilirsiniz:

ekran -r

Ve sonra sadece ^ C veya başka bir şeyle sonlandırın.

İhtiyacınız olan süreçte yeniden bağlantı kurabilme ve bağlantıyı kesebilmenin güzelliğinin yanı sıra 'ekran', programınızın üretebileceği herhangi bir stdout'u () yakalayacaktır.


Ancak bu konulardaki kişisel tercihim, bir sürecin başlatılmasını ve durdurulmasını yöneten bir kontrol programına sahip olmaktır. Bu biraz karmaşık olabilir ve tartışmasız karmaşık bir komut dosyası gerektirir. Ve herhangi bir senaryo gibi, bunu yapmanın onlarca iyi yolu var. Uygulamaları başlatmak ve durdurmak için rutin olarak kullandığım bir yöntemin bash örneğini ekledim. Göreviniz basitse, doğrudan kontrol komut dosyasına ekleyebilirsiniz - veya bu kontrol komut dosyasının başka bir harici programı çağırmasını sağlayabilirsiniz. Bu örneğin hiçbir şekilde süreci yönetme açısından kapsamlı olmadığını unutmayın. Gibi senaryoların olasılığını dışarıda bıraktım: "start" seçeneğini kullandığınızda betiğin zaten çalışmadığından emin olmak, çalışan PID'nin aslında başlattığınız işlem olduğunu doğrulamak (örn. t öldü ve aynı PID kullanılarak başka bir işlem başlatıldı) ve betiğin ilk 'öldürme' isteğinde gerçekten yanıt verdiğini (çıktığını) doğruladı. Tüm bu kontrolleri yapmak karmaşıklaşabilir ve örneği çok uzun ve karmaşık yapmak istemedim. Kabuk komut dosyalarınızı uygulamak için örneği değiştirmek isteyebilirsiniz.

Aşağıdaki kodu "programctl" adlı bir dosyaya kaydedin, komutla yürütülebilir yapın:

chmod 755 program programı

Ardından dosyayı düzenleyin ve kodunuzu / komut dosyanızı "myscript" ile başlayan vaka bölümüne ekleyin.

Her şey hazır olduğunda, "programctl" ifadesinin geçerli dizinde olduğu varsayılarak, programınızı aşağıdakilerle başlatabilirsiniz:

./programctl başlangıç

Ve şununla durdur:

./programctl durdurma

Şerefe.

#!/bin/bash
# Description:  A wrapper script used to stop/start another script.

#--------------------------------------
# Define Global Environment Settings:
#--------------------------------------

# Name and location of a persistent PID file

PIDFILE="/tmp/tmpfile-$LOGNAME.txt"

#--------------------------------------
# Check command line option and run...
# Note that "myscript" should not
# provided by the user.
#--------------------------------------

case $1
in
    myscript)
        # This is where your script would go.
        # If this is a routine 'bash' shell script, you can enter
        # the script below as illustrated in the example.  
        # Or you could simply provide the path and parameters
        # to another script such as /dir/name/command -options

        # Example of an embedded script:

        while true
        do
            # do something over and over...
            sleep 1
        done

        # Example of an external script:

        /usr/local/bin/longrun -x
    ;;

    start)
        # Start your script in the background.
        # (Note that this is a recursive call to the wrapper
        #  itself that effectively runs your script located above.)
        $0 myscript &

        # Save the backgound job process number into a file.
        jobs -p > $PIDFILE

        # Disconnect the job from this shell.
        # (Note that 'disown' command is only in the 'bash' shell.)
        disown %1

        # Print a message indicating the script has been started
        echo "Script has been started..."
    ;;

    stop)
        # Read the process number into the variable called PID
        read PID < $PIDFILE

        # Remove the PIDFILE
        rm -f $PIDFILE

        # Send a 'terminate' signal to process
        kill $PID

        # Print a message indicating the script has been stopped
        echo "Script has been stopped..."
    ;;

    *)
        # Print a "usage" message in case no arguments are supplied
        echo "Usage: $0 start | stop"
    ;;
esac

Önerdiğiniz "ekran" yöntemini denedim ve güzel çalışıyor. Henüz ikinci yöntemi denemiyorum. Cevap için teşekkür ederim.
light94
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.