Arka plan işleminin işlem kimliği nasıl alınır?


375

Kabuk betiğimden bir arka plan işlemi başlatıyorum ve betiğim bittiğinde bu işlemi öldürmek istiyorum.

Bu işlemin PID'sini kabuk betiğimden nasıl alabilirim? Gördüğüm kadarıyla değişken $!, arka plan sürecini değil, geçerli komut dosyasının PID'sini içerir.


8
, $! doğru. Komut dosyasını BG'de başlattığınızdan emin misiniz? örnek lütfen.
pixelbeat

7
Evet $! doğru. Ben hatalıydım.
Volodymyr Bezuglyy

11
$$, geçerli komut dosyası PID'sini içerir.
HUB

Yanıtlar:


583

Arka plan işleminin PID'sini başlattığınızda kaydetmeniz gerekir:

foo &
FOO_PID=$!
# do other stuff
kill $FOO_PID

İş kontrolünü kullanamazsınız, çünkü bu etkileşimli bir özelliktir ve bir kontrol terminaline bağlıdır. Bir komut dosyasının iliştirilmiş bir terminali olması gerekmez, bu nedenle iş kontrolünün mutlaka kullanılabilir olması gerekmez.


22
$ 'Dan beri! son arka plan işleminin pid'ini döndürür. Bunun mümkün olduğunu arasında bir şey başlar foove $!ve biz yerine bir şeyler olduğu anlamına pid almak foo's?
WiSaGaN

53
@WiSaGaN: Hayır. Bu çizgiler arasında hiçbir şey yok. Sistemdeki diğer etkinlikler bunu etkilemez. , $! o kabuktaki son arka plan işleminin PID'sine genişler .
camh

8
... foobirden fazla borulu komut olması durumunda sizi hortumlar (örn. tail -f somefile.txt | grep sometext). Bu gibi durumlarda, aradığınız $!şey buysa, kuyruk komutundan ziyade grep komutunun PID'sini alırsınız . Sen kullanmanız gerekecektir jobsveya psbu durumda sever ya.
John Rix

1
@JohnRix: Mutlaka değil. Sen pid alacak grep, ama bunu öldürürseniz, boruya yazmaya çalışırken kuyruk SIGPIPE alacak. Ancak herhangi bir zor süreç yönetimi / kontrolüne girmeye çalıştığınızda, bash / shell oldukça acı verici hale gelir.
camh

5
Başka bir değerli çözüm önerilmektedir (bir cevaba yorum) Yeni başlayan sürecin pid nasıl alınır : oh, ve "oneliner": /bin/sh -c 'echo $$>/tmp/my.pid && exec program args' &- sysfault 24 Kasım 'da 14:28
imz - Ivan Zakharyaschev

148

jobs -lBelirli bir işe erişmek için komutu kullanabilirsinizL

^Z
[1]+  Stopped                 guard

my_mac:workspace r$ jobs -l
[1]+ 46841 Suspended: 18           guard

Bu durumda, 46841 PID'dir.

Gönderen help jobs:

-l İşlerin süreç grubu kimliğini ve çalışma dizinini bildirme.

jobs -p yalnızca PID'leri gösteren başka bir seçenektir.


Bunu bir kabuk komut dosyasında kullanmak için çıktıyı işlemeniz gerekir.
Phil

6
@Phil Yalnızca pids listelemek için: jobs -p. Belirli bir işin pid'ini listelemek için: işler -p% 3. Çıktı işlemeye gerek yok.
Erik Aronesty

1
@Erik farklı komutlar / argümanlar ile yorumumun bağlamını değiştirirsiniz. Önerilen ek argüman olmadan, çıktı işleme gerektirir. Cevaba bir iyileştirme öner!
Phil

PID'yi $!başlattıktan hemen sonra kaydetmek, çoğu durumda daha taşınabilir ve daha basittir. Şu anda kabul edilen cevap budur.
üçlü

jobs -pjobs -lLubuntu 16.4
Timo

46
  • $$ şu anki komut dosyasının pid'i
  • $! son arka plan sürecinin pididir

İşte bir bash oturumundan örnek bir konuşma metni ( %1görüldüğü gibi arka plan işleminin sıralı sayısını ifade eder jobs):

$ echo $$
3748

$ sleep 100 &
[1] 192

$ echo $!
192

$ kill %1

[1]+  Terminated              sleep 100

yankı %1oysa benim Ubuntu üzerine plan işlemi dönmez echo $!yapar
Timo'yu

25

Bir bash betiğinin tüm alt sürecini öldürmenin daha basit bir yolu:

pkill -P $$

-PBayrak ile aynı şekilde çalışır pkillve pgrepsadece birlikte, çocuk süreçlerini alır - pkillçocuk süreçleri öldürüp olsun pgrepçocuk PID'ler bekletilmektedir.


Çok uygun! Bu, açık işlemleri arka planda bırakmamanızı sağlamanın en iyi yoludur.
lepe

@ lepe: Pek sayılmaz. Eğer bir büyükbaba, bu işe yaramaz: sonra bash -c 'bash -c "sleep 300 &"' & çalışan pgrep -P $$gösterileri şey, uyku kabuğundan doğrudan çocuk olmayacak çünkü.
petre

1
@AlexeyPolonsky: öyle olmalı: bir kabuğun değil, bir kabuğun tüm alt süreçlerini öldürün. Çünkü $$mevcut kabuğu ifade eder.
Timo

performans bash -c 'bash -c "sleep 300 &"' & ; pgrep -P $$, stdout [1] <pid>. So at least it shows something, but this is probably not the output of pgrep` alıyorum
Timo

İşlemler bile bunları ana işlemden çıkarabilir. Basit hile çatal çağırmak (bir torun oluşturmak) ve sonra sadece torun işi yapmaya devam ederken çocuk süreci çıkmak izin. (daemonization anahtar kelimedir) Ancak çocuk çok fazla koşmaya devam etse bile -P torunlara sinyal yaymak için yeterli değildir. Tüm bağımlı işlem ağacını takip etmek için pstree gibi bir araç gereklidir. Ancak bu, ebeveynleri süreç 1 olduğu için süreçten başlayan cinleri yakalamaz. Örneğin:bash -c 'bash -c "sleep 10 & wait $!"' & sleep 0.1; pstree -p $$
Pauli Nieminen

4

Ben de bunu yaptım. Check it out, umarım yardımcı olabilir.

#!/bin/bash
#
# So something to show.
echo "UNO" >  UNO.txt
echo "DOS" >  DOS.txt
#
# Initialize Pid List
dPidLst=""
#
# Generate background processes
tail -f UNO.txt&
dPidLst="$dPidLst $!"
tail -f DOS.txt&
dPidLst="$dPidLst $!"
#
# Report process IDs
echo PID=$$
echo dPidLst=$dPidLst
#
# Show process on current shell
ps -f
#
# Start killing background processes from list
for dPid in $dPidLst
do
        echo killing $dPid. Process is still there.
        ps | grep $dPid
        kill $dPid
        ps | grep $dPid
        echo Just ran "'"ps"'" command, $dPid must not show again.
done

Sonra sadece şu şekilde çalıştırın: ./bgkill.shtabii ki uygun izinlerle

root@umsstd22 [P]:~# ./bgkill.sh
PID=23757
dPidLst= 23758 23759
UNO
DOS
UID        PID  PPID  C STIME TTY          TIME CMD
root      3937  3935  0 11:07 pts/5    00:00:00 -bash
root     23757  3937  0 11:55 pts/5    00:00:00 /bin/bash ./bgkill.sh
root     23758 23757  0 11:55 pts/5    00:00:00 tail -f UNO.txt
root     23759 23757  0 11:55 pts/5    00:00:00 tail -f DOS.txt
root     23760 23757  0 11:55 pts/5    00:00:00 ps -f
killing 23758. Process is still there.
23758 pts/5    00:00:00 tail
./bgkill.sh: line 24: 23758 Terminated              tail -f UNO.txt
Just ran 'ps' command, 23758 must not show again.
killing 23759. Process is still there.
23759 pts/5    00:00:00 tail
./bgkill.sh: line 24: 23759 Terminated              tail -f DOS.txt
Just ran 'ps' command, 23759 must not show again.
root@umsstd22 [P]:~# ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
root      3937  3935  0 11:07 pts/5    00:00:00 -bash
root     24200  3937  0 11:56 pts/5    00:00:00 ps -f

3

Ayrıca pstree'yi de kullanabilirsiniz:

pstree -p user

Bu genellikle "kullanıcı" için tüm işlemlerin metin temsilini verir ve -p seçeneği process-id değerini verir. Anladığım kadarıyla, süreçlerin mevcut kabuğa ait olmasına bağlı değildir. Aynı zamanda çatalları gösterir.


1
Bunu bir kabuk betiğinde kullanmak için, çıktıyı yoğun bir şekilde işlemeniz gerekir.
Phil

1

pgrepsize bir üst sürecin tüm alt PID'lerini alabilirsiniz. Daha önce $$de belirtildiği gibi , mevcut komut dosyaları PID'sidir. Yani, kendinden sonra temizleyen bir komut dosyası istiyorsanız, bu hile yapmalıdır:

trap 'kill $( pgrep -P $$ | tr "\n" " " )' SIGINT SIGTERM EXIT

Bu çok şeyi öldürmez mi?
Phil

Evet, soru, bazı arka plan çocuklarının çıkışta hayatta kalmasını hiç söylemedi .
errant.info

trap 'pkill -P $$' SIGING SIGTERM EXITdaha basit görünüyor, ama test etmedim.
petre

Uyumluluk için SIGöneki kullanmayın . Bu uygulamalar bu POSIX tarafından ama sadece bir uzantısı olarak bırakılır olabilir destekler: pubs.opengroup.org/onlinepubs/007904975/utilities/trap.html örneğin çizgi kabuk buna gerek yoktur.
josch
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.