Làm cách nào để kiểm tra nếu id quá trình (PID) tồn tại


184

Trong tập lệnh bash, tôi muốn làm như sau (bằng mã giả):

if [ a process exists with $PID ]; then

    kill $PID 

fi

Biểu thức thích hợp cho câu lệnh có điều kiện là gì?

Câu trả lời:


182

Để kiểm tra sự tồn tại của một quá trình, sử dụng

kill -0 $pid

Nhưng đúng như @unwind đã nói, dù sao bạn cũng sẽ giết nó, chỉ cần

kill $pid

hoặc bạn sẽ có một điều kiện cuộc đua.

Nếu bạn muốn bỏ qua đầu ra văn bản của killvà làm một cái gì đó dựa trên mã thoát, bạn có thể

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

1
nhìn vào trang man, kill -0 là: "mã thoát cho biết nếu tín hiệu có thể được gửi đi". Vì vậy, thực tế này có giết chết một quá trình, hoặc chỉ cho bạn biết nếu nó có thể bị giết?
Richard H

23
killđược đặt tên sai ở chỗ nó không nhất thiết phải giết quá trình. Nó chỉ gửi quá trình một tín hiệu. kill $PIDtương đương với kill -15 $PID, nó gửi tín hiệu 15, SIGTERM đến tiến trình, đây là một lệnh để chấm dứt. Không có tín hiệu 0, đó là một giá trị đặc biệt killđể chỉ kiểm tra xem tín hiệu có thể được gửi đến quá trình hay không, điều này dành cho hầu hết các mục đích tương đương ít nhiều với việc kiểm tra xem nó có tồn tại hay không. Xem linux.die.net/man/2/killlinux.die.net/man/7/signal
Christoffer Hammarström

43
Điều này có vấn đề là nếu quy trình không thuộc sở hữu của người dùng đang chạy, bạn có thể không có quyền gọi kill -0. Tốt hơn là sử dụng ps -p $ PID> / dev / null 2> & 1, cho phép bạn xem trạng thái quá trình, ngay cả khi bạn không có quyền gửi tín hiệu.
mckoss

6
@mckoss: Trong trường hợp đó anh ta không thể giết nó.
Christoffer Hammarström

2
Vì vậy, tôi đoán - để sử dụng kill -0, trên thực tế, tôi phải làm điều này: kill -0 25667 ; echo $?- và sau đó nếu tôi được 0trả lại, thì quá trình với PID đó có thể bị giết; và nếu quá trình PID (nói) không tồn tại, thì $?sẽ có 1, cho thấy sự thất bại. Đúng không?
sdaau

264

Cách tốt nhất là:

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

Vấn đề với:

kill -0 $PID

là mã thoát sẽ khác không ngay cả khi pid đang chạy và bạn không có quyền giết nó. Ví dụ:

kill -0 1

kill -0 $non-running-pid

có một mã thoát không thể phân biệt (khác không) cho một người dùng bình thường, nhưng quá trình init (PID 1) chắc chắn đang chạy.

THẢO LUẬN

Các câu trả lời thảo luận về điều kiện giết và chủng tộc là hoàn toàn chính xác nếu cơ thể của bài kiểm tra là "giết". Tôi đã tìm kiếm chung chung " làm thế nào để bạn kiểm tra sự tồn tại của PID trong bash ".

Phương thức / Proc rất thú vị, nhưng trong một số trường hợp, phá vỡ tinh thần của sự trừu tượng lệnh "ps", tức là bạn không cần phải tìm trong / Proc vì nếu Linus quyết định gọi tệp "exe" thì sao?


1
ps -p luôn trả về trạng thái 0 cho tôi
IttayD

1
ps -p #### hoạt động tốt với tôi trong Ubuntu 14.04, cảm ơn +1!
Ligemer 23/2/2016

3
ps -p luôn trả về mã trạng thái 0 trong os x vì nó in ra một danh sách quy trình trống khi nó không khớp với bất kỳ quy trình đang chạy nào
Douglas Correa

Tôi có thể xác nhận rằng trên macOS Sierra, điều này hoạt động. Ngoài ra, điều -pnày là không cần thiết, ít nhất là trong trường hợp đó. ps $PIDcó kết quả chính xác như nhau.
dùng137369

Tính di động là một lý do tốt để tránh sử dụng / Proc, nhưng linux phá vỡ ABI của nó không phải là một kịch bản tôi đặc biệt lo lắng.
David Roundy

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

hoặc là

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

Ở dạng sau, -o pid=là một định dạng đầu ra để chỉ hiển thị cột ID quá trình không có tiêu đề. Các trích dẫn là cần thiết cho toán tử chuỗi không trống -nđể đưa ra kết quả hợp lệ.


1
Phương thức thứ hai cũng hoạt động trên Mac, như là một điểm cộng bổ sung (Mac OS X không có / Proc FS). Tuy nhiên, bạn có thể tránh sử dụng một mạng con và sử dụng tính năng này trên cả Mac và Linux:if ps -p"$PID" -o "pid=" >/dev/null 2>&1; then echo "Process is running..."; fi
Will

Thật không may, pscác tùy chọn và tính năng có xu hướng khác nhau giữa các nền tảng, vì vậy nó vẫn không hoàn toàn di động.
tripleee

1
nếu $PIDtrống thì [ -e /proc/$PID ]vẫn trả về true, vì /proc/thư mục vẫn tồn tại.
Magne

34

pslệnh với -p $PIDcó thể làm điều này:

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

11

Bạn có hai cách:

Hãy bắt đầu bằng cách tìm kiếm một ứng dụng cụ thể trong máy tính xách tay của tôi:

[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

Tất cả các ví dụ bây giờ sẽ tìm kiếm PID 3358.

Cách thứ nhất : Chạy "ps aux" và grep cho PID trong cột thứ hai. Trong ví dụ này tôi tìm firefox, và sau đó là PID:

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

Vì vậy, mã của bạn sẽ là:

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

Cách thứ hai : Chỉ cần tìm một cái gì đó trong /proc/$PIDthư mục. Tôi đang sử dụng "exe" trong ví dụ này, nhưng bạn có thể sử dụng bất cứ thứ gì khác.

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

Vì vậy, mã của bạn sẽ là:

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

BTW: có chuyện gì với kill -9 $PID || true?


BIÊN TẬP:

Sau khi suy nghĩ về nó trong vài tháng .. (khoảng 24 ...) ý tưởng ban đầu tôi đưa ra ở đây là một bản hack hay, nhưng rất khó tin. Mặc dù nó dạy một vài chi tiết triển khai của Linux, nhưng nó sẽ không hoạt động trên Mac, Solaris hoặc * BSD. Nó thậm chí có thể thất bại trên các nhân Linux trong tương lai. Vui lòng - sử dụng "ps" như được mô tả trong các phản hồi khác.


ít nhất là phần kill -9 có vẻ sai (không giết được các quy trình con)
Nurettin

Tại sao tôi nhận được [: thiếu `] 'khi sử dụng cách đầu tiên?
tenmiles

1
/proc/$PID/exekhông phải là một tập tin thông thường Vì vậy, [ -f /proc/$PID/exe ]sẽ luôn trả về một falsekết quả. Hãy thử [ -h /proc/$PID/exe ].
Alexander Yancharuk

8

Có vẻ như bạn muốn

wait $PID

Nó sẽ trở lại khi $pidkết thúc.

Nếu không bạn có thể sử dụng

ps -p $PID

để kiểm tra xem quy trình có còn tồn tại không (điều này hiệu quả hơn kill -0 $pidvì nó sẽ hoạt động ngay cả khi bạn không sở hữu pid).


1
chờ đợi không hiệu quả vì quá trình nên là con của vỏ hiện tại hoặc nó sẽ cho:pid 123 is not a child of this shell
Calumah

7

Tôi nghĩ rằng đó là một giải pháp tồi, mở ra cho các điều kiện chủng tộc. Điều gì xảy ra nếu quá trình chết giữa thử nghiệm của bạn và lời kêu gọi giết của bạn? Sau đó giết sẽ thất bại. Vậy tại sao không thử giết trong mọi trường hợp và kiểm tra giá trị trả về của nó để tìm hiểu xem nó đã đi như thế nào?


Không may mã +1 của kill (1) không phân biệt các tình huống lỗi khác nhau (có vẻ như nó tăng giá trị thoát lên một cho mỗi quá trình mà nó không báo hiệu). nếu OP không ngại viết trình bao bọc kill (2) của riêng họ, anh ta có thể thoát nó với các giá trị khác nhau dựa trên giá trị của ERRNO sau khi gọi (2) lệnh kill không thành công.
chỉ là ai đó

tại thời điểm này tôi chỉ thực hiện kill -9 mà không kiểm tra - tôi chỉ gặp lỗi "quá trình không tồn tại" nếu nó không tồn tại mà không gọn gàng. Làm thế nào tôi có thể kiểm tra những gì đã xảy ra?
Richard H

14
Đừng bất cẩn kill -9. Điều đó ngay lập tức giết chết quá trình cho nó không có cơ hội để làm sạch sau đó. Thay vào đó sử dụng killtương đương với kill -15. Nếu điều đó không hiệu quả, bạn nên tìm hiểu lý do tại sao và chỉ là lần sử dụng cuối cùng kill -9.
Christoffer Hammarström

0

Ở đây tôi lưu trữ PID trong một tệp có tên .pid (là loại like / run / ...) và chỉ thực thi tập lệnh nếu chưa được thực thi.

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

lưu ý: có một điều kiện cuộc đua vì nó không kiểm tra xem pid đó được gọi như thế nào. nếu hệ thống được khởi động lại và .pid tồn tại nhưng được sử dụng bởi một ứng dụng khác, điều này có thể dẫn đến 'hậu quả không lường trước'.


0

Ví dụ: trong GNU / Linux, bạn có thể sử dụng:

Pid=$(pidof `process_name`)

if [ $Pid > 0 ]; then

   do something
else

   do something
fi 

Hoặc một cái gì đó như

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

và điều đó cho bạn thấy tên của ứng dụng, chỉ tên không có ID.


1
pidofkhông trả về số âm, vì một PID âm không có ý nghĩa gì và bạn không thể giết init, do đó, điều kiện của bạn không có ý nghĩa gì (và bên cạnh đó, bạn cần phải thoát khỏi >để ngăn nó thực hiện chuyển hướng). Bạn muốn kiểm tra một kết quả trống, nhưng tất nhiên, giống như bất kỳ công cụ tử tế nào, pidofđặt mã thoát để cho bạn biết liệu nó có hoạt động hay không, vì vậy giải pháp thích hợp là if Pid=$(pidof 'process_name'); then ...hoặc (nếu bạn sẽ không cần giá trị Pidsau này)if pidof 'process_name'; then...
tripleee

@tripleee đúng là pidofví dụ đầy hiểu lầm về cách testhoạt động của bash . gnu.org/software/bash/manual/html_node/ từ
Bruno Bronosky

0

mã bên dưới kiểm tra nếu quá trình của tôi đang chạy, nếu vậy không làm gì.

hãy kiểm tra tin nhắn mới từ Amazon SQS mỗi giờ và chỉ khi quá trình không chạy.

#!/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 $?
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.