Cara memeriksa apakah ada id proses (PID)

184

Dalam skrip bash, saya ingin melakukan hal berikut (dalam pseudo-code):

if [ a process exists with $PID ]; then

    kill $PID 

fi

Apa ungkapan yang sesuai untuk pernyataan kondisional?

Richard H
sumber

Jawaban:

182

Untuk memeriksa keberadaan suatu proses, gunakan

kill -0 $pid

Tapi seperti yang dikatakan @wwind, jika kamu akan membunuhnya, cukup

kill $pid

atau Anda akan memiliki kondisi balapan.

Jika Anda ingin mengabaikan output teks killdan melakukan sesuatu berdasarkan kode keluar, Anda bisa

if ! kill $pid > /dev/null 2>&1; then
    echo "Could not send SIGTERM to process $pid" >&2
fi
Christoffer Hammarström
sumber
1
melihat halaman manual, kill -0 adalah: "kode keluar menunjukkan jika sinyal dapat dikirim". Jadi, apakah ini benar-benar membunuh suatu proses, atau hanya memberitahu Anda jika itu bisa dibunuh?
Richard H
24
killagak keliru karena tidak selalu membunuh prosesnya. Itu hanya mengirimkan proses sinyal. kill $PIDsetara dengan kill -15 $PID, yang mengirimkan sinyal 15, SIGTERM ke proses, yang merupakan instruksi untuk mengakhiri. Tidak ada sinyal 0, itu adalah nilai khusus yang mengatakan killuntuk hanya memeriksa apakah sinyal dapat dikirim ke proses, yang untuk sebagian besar tujuan kurang lebih setara dengan memeriksa jika ada. Lihat linux.die.net/man/2/kill dan linux.die.net/man/7/signal
Christoffer Hammarström
43
Ini memiliki masalah bahwa jika proses tidak dimiliki oleh pengguna yang sedang berjalan, Anda mungkin tidak memiliki izin untuk memanggil kill -0. Lebih baik menggunakan ps -p $ PID> / dev / null 2> & 1, yang memungkinkan Anda melihat status proses, bahkan jika Anda tidak memiliki izin untuk mengirim sinyal.
mckoss
6
@ Mattck: Kalau begitu, dia tidak bisa membunuhnya.
Christoffer Hammarström
2
Jadi, saya kira - untuk digunakan kill -0, saya, pada kenyataannya, harus melakukan ini: kill -0 25667 ; echo $?- dan kemudian jika saya mendapatkan 0kembali, maka proses dengan PID itu dapat dibunuh; dan jika proses PID (katakanlah) tidak ada, $?akan 1, menunjukkan kegagalan. Apakah itu benar?
sdaau
264

Cara terbaik adalah:

if ps -p $PID > /dev/null
then
   echo "$PID is running"
   # Do something knowing the pid exists, i.e. the process with $PID is running
fi

Masalah dengan:

kill -0 $PID

adalah kode keluar akan menjadi nol bahkan jika pid sedang berjalan dan Anda tidak memiliki izin untuk membunuhnya. Sebagai contoh:

kill -0 1

dan

kill -0 $non-running-pid

memiliki kode keluar yang tidak dapat dibedakan (tidak nol) untuk pengguna normal, tetapi proses init (PID 1) sudah pasti berjalan.

DISKUSI

Jawaban yang membahas kondisi membunuh dan ras benar jika tubuh tes adalah "membunuh". Saya datang mencari jenderal " bagaimana Anda menguji keberadaan PID di bash ".

Metode / proc itu menarik, tetapi dalam beberapa hal mematahkan semangat abstraksi perintah "ps", yaitu Anda tidak perlu pergi mencari di / proc karena bagaimana jika Linus memutuskan untuk memanggil file "exe" sesuatu yang lain?

FDS
sumber
1
ps -p selalu mengembalikan status 0 untuk saya
IttayD
1
ps -p #### bekerja dengan baik untuk saya di bawah Ubuntu 14.04, +1 terima kasih!
Ligemer
3
ps -p selalu mengembalikan kode status 0 di os x karena mencetak daftar proses kosong ketika tidak cocok dengan proses yang sedang berjalan
Douglas Correa
Saya dapat mengkonfirmasi bahwa pada macOS Sierra, ini berfungsi. Juga, -pitu tidak perlu, setidaknya dalam kasus itu. ps $PIDmemiliki hasil yang sama persis.
user137369
Portabilitas adalah alasan yang baik untuk menghindari penggunaan / proc, tetapi Linux melanggar ABI-nya bukan skenario yang saya khawatirkan.
David Roundy
67
if [ -n "$PID" -a -e /proc/$PID ]; then
    echo "process exists"
fi

atau

if [ -n "$(ps -p $PID -o pid=)" ]

Dalam bentuk yang terakhir, -o pid=adalah format output untuk menampilkan hanya kolom ID proses tanpa header. Kutipan diperlukan untuk operator string yang tidak kosong -nuntuk memberikan hasil yang valid.

pengguna2683246
sumber
1
Metode kedua juga berfungsi pada Mac, sebagai tambah tambah (Mac OS X tidak memiliki / proc FS). Anda dapat, bagaimanapun, menghindari menggunakan subkulit dan menggunakan ini pada Mac dan Linux:if ps -p"$PID" -o "pid=" >/dev/null 2>&1; then echo "Process is running..."; fi
Will
Sayangnya, psopsi dan fitur cenderung bervariasi antar platform, sehingga masih belum sepenuhnya portabel.
tripleee
1
jika $PIDkosong maka [ -e /proc/$PID ]akan tetap benar, karena /proc/direktori masih ada.
Magne
34

psperintah dengan -p $PIDdapat melakukan ini:

$ ps -p 3531
  PID TTY          TIME CMD
 3531 ?        00:03:07 emacs
oherrala
sumber
11

Anda memiliki dua cara:

Mari kita mulai dengan mencari aplikasi spesifik di laptop saya:

[root@pinky:~]# ps fax | grep mozilla
 3358 ?        S      0:00  \_ /bin/sh /usr/lib/firefox-3.5/run-mozilla.sh /usr/lib/firefox-3.5/firefox
16198 pts/2    S+     0:00              \_ grep mozilla

Semua contoh sekarang akan mencari PID 3358.

Cara pertama : Jalankan "ps aux" dan grep untuk PID di kolom kedua. Dalam contoh ini saya mencari firefox, dan kemudian untuk itu PID:

[root@pinky:~]# ps aux | awk '{print $2 }' | grep 3358
3358

Jadi kode Anda adalah:

if [ ps aux | awk '{print $2 }' | grep -q $PID 2> /dev/null ]; then
    kill $PID 
fi

Cara kedua : Cukup cari sesuatu di /proc/$PIDdirektori. Saya menggunakan "exe" dalam contoh ini, tetapi Anda dapat menggunakan hal lain.

[root@pinky:~]# ls -l /proc/3358/exe 
lrwxrwxrwx. 1 elcuco elcuco 0 2010-06-15 12:33 /proc/3358/exe -> /bin/bash

Jadi kode Anda adalah:

if [ -f /proc/$PID/exe ]; then
    kill $PID 
fi

BTW: ada apa dengan itu kill -9 $PID || true?


EDIT:

Setelah memikirkannya selama beberapa bulan .. (sekitar 24 ...) ide orisinal yang saya berikan di sini adalah hack yang bagus, tetapi sangat tidak bisa diport. Sementara itu mengajarkan beberapa detail implementasi Linux, itu akan gagal bekerja pada Mac, Solaris atau * BSD Bahkan mungkin gagal di kernel Linux masa depan. Silakan - gunakan "ps" seperti yang dijelaskan dalam tanggapan lain.

elcuco
sumber
setidaknya bagian -9 kill tampaknya salah (tidak membunuh subproses)
nurettin
Mengapa saya mendapatkan [: hilang `] 'saat menggunakan cara pertama?
Tenmiles
1
/proc/$PID/exebukan file biasa. Jadi, [ -f /proc/$PID/exe ]akan selalu mengembalikan falsehasilnya. Coba [ -h /proc/$PID/exe ].
Alexander Yancharuk
8

Sepertinya kamu mau

wait $PID

yang akan kembali saat $pidselesai.

Kalau tidak, Anda bisa menggunakan

ps -p $PID

untuk memeriksa apakah prosesnya masih hidup (ini lebih efektif daripada kill -0 $pidkarena itu akan bekerja bahkan jika Anda tidak memiliki pid).

Gagan Gami
sumber
1
menunggu tidak begitu efektif karena proses seharusnya adalah anak dari shell saat ini atau itu akan memberikan:pid 123 is not a child of this shell
Calumah
7

Saya pikir itu adalah solusi buruk, yang membuka untuk kondisi balapan. Bagaimana jika proses mati antara pengujian Anda dan panggilan Anda untuk membunuh? Maka membunuh akan gagal. Jadi mengapa tidak coba saja kill dalam semua kasus, dan periksa nilai kembalinya untuk mengetahui bagaimana hasilnya?

beristirahat
sumber
+1 sayangnya kill (1) kode keluar tidak membedakan situasi kesalahan yang berbeda (sepertinya itu menambah nilai keluar dengan satu untuk setiap proses gagal memberi sinyal). jika OP tidak keberatan menulis wrapper kill (2) mereka sendiri, ia bisa mengeluarkannya dengan nilai yang berbeda berdasarkan nilai ERRNO setelah panggilan kill (2) gagal.
hanya seseorang
saat ini saya hanya melakukan kill -9 tanpa cek - saya hanya mendapatkan kesalahan "proses tidak ada" jika tidak ada yang tidak terlalu rapi. Bagaimana saya menguji apa yang terjadi?
Richard H
14
Jangan sembarangan kill -9. Itu hanya langsung membunuh proses sehingga tidak ada kesempatan untuk membersihkan setelah itu sendiri. Alih-alih menggunakan killyang setara dengan kill -15. Jika itu tidak berhasil, Anda harus mencari tahu alasannya, dan hanya sebagai penggunaan terakhir kill -9.
Christoffer Hammarström
0

di sini saya menyimpan PID dalam file bernama .pid (yang seperti / run / ...) dan hanya menjalankan skrip jika belum dieksekusi.

#!/bin/bash
if [ -f .pid ]; then
  read pid < .pid
  echo $pid
  ps -p $pid > /dev/null
  r=$?
  if [ $r -eq 0 ]; then
    echo "$pid is currently running, not executing $0 twice, exiting now..."
    exit 1
  fi
fi

echo $$ > .pid

# do things here

rm .pid

Catatan: ada kondisi lomba karena tidak memeriksa bagaimana pid itu disebut. jika sistem di-boot ulang dan .pid ada tetapi digunakan oleh aplikasi yang berbeda ini dapat menyebabkan 'konsekuensi yang tidak terduga'.

sihir tidak valid
sumber
0

Sebagai contoh di GNU / Linux Anda dapat menggunakan:

Pid=$(pidof `process_name`)

if [ $Pid > 0 ]; then

   do something
else

   do something
fi 

Atau semacamnya

Pin=$(ps -A | grep name | awk 'print $4}')
echo $PIN

dan itu menunjukkan Anda nama aplikasi, hanya nama tanpa ID.

inukaze
sumber
1
pidoftidak mengembalikan angka negatif, karena PID negatif tidak masuk akal, dan Anda tidak dapat membunuh init, sehingga persyaratan Anda tidak masuk akal (dan selain itu, Anda harus melarikan diri dari >untuk mencegahnya melakukan pengalihan). Anda ingin memeriksa hasil yang kosong, tetapi tentu saja, seperti alat yang layak, pidofmenetapkan kode keluar untuk memberi tahu Anda apakah itu berhasil, jadi solusi yang tepat adalah if Pid=$(pidof 'process_name'); then ...atau (jika Anda tidak memerlukan nilainya Pidnanti) cukupif pidof 'process_name'; then...
tripleee
@ tripleee benar, pidofcontohnya penuh dengan kesalahpahaman tentang cara testkerja bash . gnu.org/software/bash/manual/html_node/…
Bruno Bronosky
0

kode di bawah memeriksa apakah proses saya sedang berjalan, jika tidak melakukan apa-apa.

mari kita periksa pesan baru dari Amazon SQS setiap jam saja dan hanya jika prosesnya tidak berjalan.

#!/bin/bash
PID=$(ps aux | grep '/usr/bin/python2.7 manage.py SES__boto3_sqs_read' | grep -v grep | awk '{print $2}')
if [[ -z $PID ]]; then
    /usr/bin/python2.7 /home/brian/djcode/proyectoONE/manage.py SES__boto3_sqs_read
else
    echo "do nothing, just smile =)"
fi
exit $?
Brian Sanchez
sumber