วิธีตรวจสอบว่ามี id กระบวนการ (PID) อยู่หรือไม่


184

ในสคริปต์ทุบตีฉันต้องการทำดังต่อไปนี้ (ในรหัสหลอก):

if [ a process exists with $PID ]; then

    kill $PID 

fi

การแสดงออกที่เหมาะสมสำหรับคำสั่งเงื่อนไขคืออะไร?

คำตอบ:


182

เพื่อตรวจสอบการมีอยู่ของกระบวนการใช้

kill -0 $pid

แต่อย่างที่ @unwind พูดถ้าคุณจะฆ่ามันล่ะ

kill $pid

หรือคุณจะมีสภาพการแข่งขัน

หากคุณต้องการที่จะละเว้นการส่งออกข้อความของkillและทำอะไรบางอย่างตามรหัสออกคุณสามารถ

if ! kill $pid > /dev/null 2>&1; then
    echo "Could not send SIGTERM to process $pid" >&2
fi

1
เมื่อดูหน้า man kill -0 คือ: "exit code ระบุว่าสัญญาณอาจถูกส่ง" ดังนั้นนี่เป็นการฆ่ากระบวนการจริงหรือแค่บอกคุณว่ามันสามารถถูกฆ่าได้หรือไม่?
Richard H

24
killค่อนข้างผิดที่ไม่จำเป็นต้องฆ่ากระบวนการ มันเพิ่งส่งสัญญาณกระบวนการ kill $PIDเทียบเท่ากับkill -15 $PIDซึ่งส่งสัญญาณ 15, SIGTERM ไปยังกระบวนการซึ่งเป็นคำสั่งให้ยุติ ไม่มีสัญญาณ 0 นั่นคือค่าพิเศษที่บอกkillให้ตรวจสอบว่าสามารถส่งสัญญาณไปยังกระบวนการได้หรือไม่ซึ่งมีจุดประสงค์ส่วนใหญ่มากกว่าหรือน้อยกว่าเทียบเท่ากับการตรวจสอบว่ามีอยู่หรือไม่ ดูlinux.die.net/man/2/killและlinux.die.net/man/7/signal
Christoffer Hammarström

43
ปัญหานี้มีปัญหาว่าหากกระบวนการไม่ได้เป็นของผู้ใช้ที่กำลังทำงานอยู่คุณอาจไม่มีสิทธิ์เรียก call -0 ดีกว่าที่จะใช้ ps -p $ PID> / dev / null 2> & 1 ซึ่งช่วยให้คุณเห็นสถานะกระบวนการแม้ว่าคุณจะไม่ได้รับอนุญาตให้ส่งสัญญาณ
mckoss

6
@mckoss: ในกรณีนี้เขาไม่สามารถฆ่ามันได้
Christoffer Hammarström

2
ดังนั้นฉันเดา - ใช้จริง ๆkill -0แล้วฉันต้องทำสิ่งนี้: kill -0 25667 ; echo $?- แล้วถ้าฉันได้รับ0คืนจากนั้นกระบวนการที่มี PID นั้นจะถูกฆ่า; และถ้ากระบวนการ PID (พูด) ไม่มีอยู่สิ่ง$?นั้นจะ1บ่งบอกถึงความล้มเหลว ถูกต้องไหม
sdaau

264

วิธีที่ดีที่สุดคือ:

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

ปัญหากับ:

kill -0 $PID

คือรหัสทางออกจะไม่เป็นศูนย์แม้ว่า pid กำลังทำงานอยู่และคุณไม่ได้รับอนุญาตให้ฆ่ามัน ตัวอย่างเช่น:

kill -0 1

และ

kill -0 $non-running-pid

มีรหัสทางออกที่แยกไม่ออก (ไม่ใช่ศูนย์) สำหรับผู้ใช้ปกติ แต่กระบวนการเริ่มต้น (PID 1) กำลังทำงานอยู่อย่างแน่นอน

อภิปรายผล

คำตอบเกี่ยวกับเงื่อนไขการฆ่าและการแข่งขันนั้นถูกต้องหากร่างของการทดสอบนั้นเป็น "การฆ่า" ฉันมาหาคำว่า " คุณจะทดสอบการมีอยู่ของ PID ได้อย่างไรในการทุบตี "

กระบวนการ / proc นั้นน่าสนใจ แต่ในบางแง่มุมทำให้จิตวิญญาณของคำสั่ง abstraction "ps" นั่นคือคุณไม่จำเป็นต้องค้นหา / proc เพราะถ้า Linus ตัดสินใจที่จะเรียกไฟล์ "exe" อย่างอื่น?


1
ps -p ส่งคืนสถานะ 0 เสมอสำหรับฉัน
IttayD

1
ps -p #### ใช้ได้ดีสำหรับฉันภายใต้ Ubuntu 14.04, +1 ขอบคุณ!
Ligemer

3
ps -p ส่งคืนรหัสสถานะ 0 ในระบบปฏิบัติการ x เสมอเพราะจะพิมพ์รายการกระบวนการที่ว่างเปล่าเมื่อไม่ตรงกับกระบวนการทำงานใด ๆ
Douglas Correa

ฉันสามารถยืนยันได้ใน macOS Sierra งานนี้ นอกจากนี้ยัง-pมีความจำเป็นอย่างน้อยในกรณีนั้น ps $PIDมีผลลัพธ์เหมือนกันทุกประการ
user137369

การพกพาเป็นเหตุผลที่ดีที่จะหลีกเลี่ยงการใช้ / proc แต่ linux การทำลาย ABI ไม่ใช่สถานการณ์ที่ฉันกังวลเป็นพิเศษ
David Roundy

67
if [ -n "$PID" -a -e /proc/$PID ]; then
    echo "process exists"
fi

หรือ

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

ในรูปแบบหลัง-o pid=เป็นรูปแบบเอาต์พุตเพื่อแสดงเฉพาะคอลัมน์ ID กระบวนการที่ไม่มีส่วนหัว เครื่องหมายคำพูดจำเป็นสำหรับตัวดำเนินการสตริงที่ไม่ว่างเปล่า-nเพื่อให้ผลลัพธ์ที่ถูกต้อง


1
วิธีที่สองก็ใช้ได้กับ Mac เช่นกันเมื่อบวก (Mac OS X ไม่มี / proc FS) อย่างไรก็ตามคุณสามารถหลีกเลี่ยงการใช้เชลล์ย่อยและใช้สิ่งนี้กับทั้ง Mac และ Linux:if ps -p"$PID" -o "pid=" >/dev/null 2>&1; then echo "Process is running..."; fi
Will

น่าเสียดายที่psตัวเลือกและคุณสมบัติต่างๆนั้นมีความแตกต่างกันระหว่างแพลตฟอร์มดังนั้นจึงยังไม่สามารถพกพาได้ทั้งหมด
tripleee

1
หาก$PIDว่างแล้ว[ -e /proc/$PID ]จะยังคงเป็นจริงเนื่องจาก/proc/ไดเรกทอรียังคงอยู่
Magne


11

คุณมีสองวิธี:

เริ่มต้นด้วยการมองหาแอปพลิเคชันเฉพาะในแล็ปท็อปของฉัน:

[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

ตัวอย่างทั้งหมดในตอนนี้จะค้นหา PID 3358

วิธีแรก : เรียกใช้ "ps aux" และ grep สำหรับ PID ในคอลัมน์ที่สอง ในตัวอย่างนี้ฉันค้นหา firefox และจากนั้น PID:

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

ดังนั้นรหัสของคุณจะเป็น:

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

วิธีที่สอง : เพียงมองหาบางอย่างใน/proc/$PIDไดเรกทอรี ฉันใช้ "exe" ในตัวอย่างนี้ แต่คุณสามารถใช้อย่างอื่นได้

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

ดังนั้นรหัสของคุณจะเป็น:

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

BTW: มีอะไรผิดปกติกับkill -9 $PID || true?


แก้ไข:

หลังจากคิดถึงเรื่องนี้ไปซักสองสามเดือน .. (ประมาณ 24 ... ) ความคิดดั้งเดิมที่ฉันให้ที่นี่เป็นแฮ็คที่ดี แต่ไม่สามารถพูดได้สูง แม้ว่ามันจะสอนรายละเอียดเกี่ยวกับการใช้งานของลีนุกซ์ แต่ก็จะล้มเหลวในการทำงานบน Mac, Solaris หรือ * BSD มันอาจจะล้มเหลวในเมล็ด Linux ในอนาคต กรุณา - ใช้ "ps" ตามที่อธิบายไว้ในคำตอบอื่น ๆ


อย่างน้อยฆ่า -9 ส่วนหนึ่งดูเหมือนว่าไม่ถูกต้อง (ไม่ได้ฆ่ากระบวนการย่อย)
Nurettin

ทำไมฉันถึงได้ [: หายไป `] 'เมื่อใช้วิธีแรก?
tenmiles

1
/proc/$PID/exeไม่ใช่ไฟล์ปกติ ดังนั้น[ -f /proc/$PID/exe ]จะส่งคืนfalseผลลัพธ์เสมอ ลอง[ -h /proc/$PID/exe ]ดู
Alexander Yancharuk

8

ดูเหมือนว่าคุณต้องการ

wait $PID

ซึ่งจะกลับมาเมื่อ$pidเสร็จสิ้น

มิฉะนั้นคุณสามารถใช้

ps -p $PID

เพื่อตรวจสอบว่ากระบวนการยังมีชีวิตอยู่หรือไม่ (นี่มีประสิทธิภาพมากกว่าkill -0 $pidเพราะจะใช้ได้แม้ว่าคุณจะไม่ได้เป็นเจ้าของ pid)


1
การรอไม่ได้ผลเท่าที่ควรจะเป็นลูกของเปลือกปัจจุบันหรือจะให้:pid 123 is not a child of this shell
Calumah

7

ฉันคิดว่านั่นเป็นทางออกที่ไม่ดีที่เปิดขึ้นสำหรับสภาพการแข่งขัน ถ้ากระบวนการตายระหว่างการทดสอบและการเรียกร้องให้ฆ่า? จากนั้นการฆ่าจะล้มเหลว ดังนั้นทำไมไม่ลองฆ่าในทุกกรณีและตรวจสอบค่าตอบแทนเพื่อดูว่ามันไปได้อย่างไร


+1 น่าเสียดายที่ฆ่า (1) รหัสทางออกของไม่ได้แยกแยะสถานการณ์ข้อผิดพลาดที่แตกต่างกัน (ดูเหมือนว่ามันจะเพิ่มค่าออกโดยหนึ่งสำหรับแต่ละกระบวนการมันล้มเหลวในการส่งสัญญาณ) ถ้า OP ไม่สนใจที่จะเขียน wrapper kill (2) ของตนเองเขาสามารถปล่อยให้มันมีค่าต่าง ๆ ตามค่าของ ERRNO หลังจากการเรียก kill (2) ที่ล้มเหลว
มีใครบางคนที่

ในขณะนี้ฉันเพิ่งฆ่า kill -9 โดยไม่มีการตรวจสอบ - ฉันเพิ่งได้รับข้อผิดพลาด "ไม่มีกระบวนการ" หากไม่มีอยู่ซึ่งไม่เป็นระเบียบมาก ฉันจะทดสอบสิ่งที่เกิดขึ้นได้อย่างไร
Richard H

14
kill -9อย่าลวก นั่นเป็นเพียงการฆ่ากระบวนการทันทีโดยไม่มีโอกาสที่จะทำความสะอาดหลังจากนั้น ใช้แทนซึ่งเทียบเท่ากับkill kill -15หากวิธีนี้ใช้ไม่ได้ผลคุณควรหาสาเหตุและใช้เพื่อการใช้งานครั้งสุดท้ายkill -9เท่านั้น
Christoffer Hammarström

0

ที่นี่ฉันเก็บ PID ในไฟล์ที่เรียกว่า. pid (ซึ่งเป็นประเภท like / run / ... ) และเรียกใช้สคริปต์เท่านั้นหากยังไม่ได้ดำเนินการ

#!/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

หมายเหตุ:มีสภาพการแข่งขันเนื่องจากไม่ได้ตรวจสอบว่ามีการเรียก pid อย่างไร หากระบบรีบูตและมี. pid อยู่ แต่มีการใช้งานโดยแอปพลิเคชันอื่นซึ่งอาจนำไปสู่


0

ตัวอย่างเช่นใน GNU / Linux คุณสามารถใช้:

Pid=$(pidof `process_name`)

if [ $Pid > 0 ]; then

   do something
else

   do something
fi 

หรืออะไรทำนองนั้น

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

และนั่นจะแสดงชื่อแอพให้คุณเห็นเพียงชื่อที่ไม่มี ID


1
pidofจะไม่ส่งคืนจำนวนลบเนื่องจาก PID เชิงลบไม่ได้มีเหตุผลใด ๆ และคุณไม่สามารถฆ่าได้initดังนั้นเงื่อนไขของคุณจึงไม่สมเหตุสมผล (และนอกจากนี้คุณต้องหลีกเลี่ยง>เพื่อป้องกันการเปลี่ยนเส้นทาง) คุณต้องการตรวจสอบผลลัพธ์ที่ว่างเปล่า แต่แน่นอนเช่นเดียวกับเครื่องมือที่ดีใด ๆpidofตั้งรหัสออกเพื่อบอกคุณว่ามันทำงานได้หรือไม่ดังนั้นทางออกที่เหมาะสมคือif Pid=$(pidof 'process_name'); then ...หรือ (ถ้าคุณไม่ต้องการค่าในPidภายหลัง) เพียงแค่if pidof 'process_name'; then...
tripleee

@tripleee ถูกต้องpidofตัวอย่างเต็มไปด้วยความเข้าใจผิดเกี่ยวกับวิธีการทุบตีtestทำงาน gnu.org/software/bash/manual/html_node/…
Bruno Bronosky

0

โค้ดด้านล่างตรวจสอบว่ากระบวนการของฉันทำงานอยู่หรือไม่

ลองตรวจสอบข้อความใหม่จาก Amazon SQS ทุก ๆ ชั่วโมงเท่านั้นและถ้ากระบวนการไม่ทำงาน

#!/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 $?
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.