Lệnh Linux / Unix để xác định xem tiến trình có đang chạy không?


97

Tôi cần một lệnh shell / bash độc lập với nền tảng (Linux / Unix | OSX) sẽ xác định xem một quy trình cụ thể có đang chạy hay không. ví dụ mysqld, httpd... Cách / lệnh đơn giản nhất để thực hiện việc này là gì?

Câu trả lời:


168

Mặc dù pidofpgreplà những công cụ tuyệt vời để xác định những gì đang chạy, nhưng thật không may, cả hai đều không khả dụng trên một số hệ điều hành. Một két an toàn hỏng chắc chắn sẽ được sử dụng như sau:ps cax | grep command

Đầu ra trên Gentoo Linux:

14484? S 0:00 apache2
14667? S 0:00 apache2
Năm 19620? Sl 0:00 apache2
21132? Ss 0:04 apache2

Đầu ra trên OS X:

42582 ?? Z 0: 00,00 (smbclient)
46529 ?? Z 0: 00,00 (smbclient)
46539 ?? Z 0: 00,00 (smbclient)
46547 ?? Z 0: 00,00 (smbclient)
46586 ?? Z 0: 00,00 (smbclient)
46594 ?? Z 0: 00,00 (smbclient)

Trên cả Linux và OS X, grep trả về mã thoát để dễ dàng kiểm tra xem quá trình có được tìm thấy hay không:

#!/bin/bash
ps cax | grep httpd > /dev/null
if [ $? -eq 0 ]; then
  echo "Process is running."
else
  echo "Process is not running."
fi

Hơn nữa, nếu bạn muốn có danh sách các PID, bạn cũng có thể dễ dàng tìm kiếm các PID đó:

ps cax | grep httpd | grep -o '^ [] * [0-9] *'

Đầu ra của ai giống nhau trên Linux và OS X:

3519 3521 3523 3524

Đầu ra của phần sau là một chuỗi trống, làm cho cách tiếp cận này an toàn cho các quá trình không chạy:

tiếng vang ps cax | grep aasdfasdf | grep -o '^[ ]*[0-9]*'

Cách tiếp cận này phù hợp để viết một bài kiểm tra chuỗi rỗng đơn giản, sau đó thậm chí lặp lại qua các PID đã phát hiện.

#!/bin/bash
PROCESS=$1
PIDS=`ps cax | grep $PROCESS | grep -o '^[ ]*[0-9]*'`
if [ -z "$PIDS" ]; then
  echo "Process not running." 1>&2
  exit 1
else
  for PID in $PIDS; do
    echo $PID
  done
fi

Bạn có thể kiểm tra nó bằng cách lưu nó vào một tệp (có tên "đang chạy") với quyền thực thi (chmod + x đang chạy) và thực thi nó với một tham số: ./running "httpd"

#!/bin/bash
ps cax | grep httpd
if [ $? -eq 0 ]; then
  echo "Process is running."
else
  echo "Process is not running."
fi

CẢNH BÁO!!!

Xin lưu ý rằng bạn chỉ đơn giản là phân tích cú pháp đầu ra ps axcó nghĩa là, như đã thấy trong đầu ra của Linux, nó không chỉ khớp trên các quy trình mà còn cả các đối số được chuyển đến chương trình đó. Tôi thực sự khuyên bạn nên càng cụ thể càng tốt khi sử dụng phương pháp này (ví dụ: ./running "mysql"cũng sẽ khớp với các quy trình 'mysqld'). Tôi thực sự khuyên bạn nên sử dụng whichđể kiểm tra một đường dẫn đầy đủ nếu có thể.


Người giới thiệu:

http://linux.about.com/od/commands/l/blcmdl1_ps.htm

http://linux.about.com/od/commands/l/blcmdl1_grep.htm


Quá trình có thể đang chạy, nhưng đã dừng lại. Vì vậy, nếu mục đích là để kiểm tra xem mysqld hoặc httpd có "up and running" (phản hồi) hay không, bạn cũng nên kiểm tra xem nó có bị dừng hay không.
oluc

2
Xin lỗi, nhưng trong khi câu trả lời chắc chắn là đúng từ quan điểm ngữ nghĩa, tôi hoàn toàn phản đối việc cố gắng tìm một quy trình bằng cách đối sánh mẫu trên vectơ đối số quy trình. Bất kỳ cách tiếp cận nào như vậy sớm muộn cũng sẽ thất bại (bạn thực sự thừa nhận với điều đó, bằng cách nói rằng cần phải kiểm tra thêm). Tôi đã thêm đề xuất của riêng mình trong một câu trả lời riêng.
peterh

6
grepcũng sẽ tìm thấy bản thân đang chạy (ví dụ như ps cax | grep randomnamesẽ luôn luôn trở về 0 vì grepphát hiện grep randomname(hy vọng điều này là rõ ràng ...) Một sửa chữa là thêm dấu ngoặc vuông xung quanh chữ cái đầu tiên của tên quá trình, ví dụ như. ps cax | grep [r]andomname.
Kyle G.

ps cax | rev | cut -f1 -d' ' | revsẽ chỉ hiển thị cột tên để phân tích cú pháp dễ dàng hơn.
Tyzoid

1
ps caxcó thể không xuất hoàn toàn tên lệnh. Ví dụ: nó in "chromium-Browse" thay vì "chromium-browser".
jarno

24

Bạn NÊN biết PID!

Tìm kiếm một quy trình bằng cách cố gắng thực hiện một số kiểu nhận dạng mẫu trên các đối số của quy trình (như pgrep "mysqld") là một chiến lược sớm muộn cũng thất bại. Điều gì sẽ xảy ra nếu bạn có hai mysqld đang chạy? Quên cách tiếp cận đó. Bạn CÓ THỂ làm nó đúng tạm thời và nó CÓ THỂ hoạt động trong một hoặc hai năm nhưng sau đó sẽ có điều gì đó xảy ra mà bạn chưa nghĩ đến.

Chỉ có id quy trình (pid) là thực sự duy nhất.

Luôn lưu trữ pid khi bạn khởi chạy thứ gì đó trong nền. Trong Bash, điều này có thể được thực hiện với $!biến Bash. Bạn sẽ tiết kiệm cho mình rất nhiều rắc rối bằng cách làm như vậy.

Cách xác định xem quá trình có đang chạy hay không (bằng pid)

Vì vậy, bây giờ câu hỏi trở thành làm thế nào để biết nếu một pid đang chạy.

Đơn giản chỉ cần làm:

ps -o pid = -p <pid>

Đây là POSIX và do đó có thể di động. Nó sẽ tự trả về pid nếu quá trình đang chạy hoặc không trả về gì nếu quá trình không chạy. Nói một cách chính xác thì lệnh sẽ trả về một cột duy nhất pid, nhưng vì chúng ta đã cho rằng một tiêu đề tiêu đề trống (thứ nằm ngay trước dấu bằng) và đây là cột duy nhất được yêu cầu nên lệnh ps sẽ không sử dụng tiêu đề. Đó là những gì chúng tôi muốn vì nó giúp phân tích cú pháp dễ dàng hơn.

Điều này sẽ hoạt động trên Linux, BSD, Solaris, v.v.

Một chiến lược khác sẽ là kiểm tra giá trị thoát từ pslệnh trên . Nó phải bằng 0 nếu quá trình đang chạy và khác 0 nếu không. Thông số kỹ thuật POSIX nói rằng psphải thoát> 0 nếu có lỗi xảy ra nhưng tôi không rõ điều gì tạo thành 'lỗi'. Vì vậy, cá nhân tôi không sử dụng chiến lược đó mặc dù tôi khá chắc chắn rằng nó sẽ hoạt động tốt trên tất cả các nền tảng Unix / Linux.


1
Ngoại trừ điều này không trả lời câu hỏi, đó là xác định xem một dịch vụ có đang chạy hay không. PID sẽ không được biết đến trong những trường hợp như vậy, do đó câu trả lời này chỉ có giá trị nếu bạn làm biết PID.
Highway of Life

2
Sai lầm. Toàn bộ quan điểm của tôi về nhận xét là hãy lùi lại một bước và nói rằng nếu lần đầu tiên bạn thấy mình ở trong tình huống bạn phải thực hiện một số hình thức grep <sometext>để tìm một quy trình nhất định thì bạn đã làm sai khi bắt đầu quy trình, IMHO. Tôi lấy nó từ câu hỏi của OP rằng thực sự anh ta có quyền kiểm soát cách thức bắt đầu quá trình.
peterh

2
"Thuật ngữ" chính xác hơn cho câu hỏi OP lẽ ra phải là "lệnh đa nền tảng để xác định xem một dịch vụ đang chạy", nó không phải là cùng một hệ thống đang chạy kiểm tra, mà là một hệ thống bên ngoài, vì vậy PID sẽ không được biết đến ở tất cả.
Highway of Life

2
Đây không phải là điều dễ hiểu. Quá trình mà bạn quan tâm có thể đã chết sau khi hệ thống hoạt động đủ lâu để PID có thể quấn quanh và một quá trình khác sau đó có thể đã được cấp phát cùng một PID mà bạn đang kiểm tra. stackoverflow.com/questions/11323410/linux-pid-recycling
claymation,

1
@claymation. Điểm công bằng. Tuy nhiên, phương pháp PID vẫn tốt hơn so với đối sánh mẫu trên các vòng quy trình vì xung đột PID khó xảy ra hơn nhiều so với việc vô tình khởi động hai phiên bản của cùng một dịch vụ. Chỉ hai xu của tôi. :-)
peterh

15

Trên hầu hết các bản phân phối Linux, bạn có thể sử dụng pidof(8).

Nó sẽ in id quy trình của tất cả các phiên bản đang chạy của các quy trình được chỉ định, hoặc không in gì nếu không có phiên bản nào đang chạy.

Ví dụ: trên hệ thống của tôi (tôi có bốn phiên bản bashvà một phiên bản remminađang chạy):

$ pidof bash remmina
6148 6147 6144 5603 21598

Trên các Liên minh khác, pgrephoặc sự kết hợp của psgrepsẽ đạt được điều tương tự, như những người khác đã chỉ ra một cách đúng đắn.


+1 pidof httpdhoạt động tốt trên Red Hat 5. Nhưng trên Red Hat 4 của tôi, pidofkhông có mặt :-(
olibre

Thật vậy, lệnh này ít phổ biến hơn tôi nghĩ, tôi đã chỉnh sửa câu trả lời của mình để làm rõ ràng hơn.
Frédéric Hamidi

Câu trả lời thực sự sạch đẹp. (trên các hệ thống được hỗ trợ). Cảm ơn bạn.
Mtl Dev

7

Điều này sẽ hoạt động trên hầu hết các phiên bản Unix, BSD và Linux:

PATH=/usr/ucb:${PATH} ps aux | grep httpd | grep -v grep

Đã thử nghiệm trên:

  • SunOS 5.10 [Do đó PATH=...]
  • Linux 2.6.32 (CentOS)
  • Linux 3.0.0 (Ubuntu)
  • Darwin 11.2.0
  • FreeBSD 9.0-ỔN ĐỊNH
  • Red Hat Enterprise Linux ES bản phát hành 4
  • Red Hat Enterprise Linux Server phiên bản 5

2
+1 Có đơn giản ps. Để tránh thứ hai greptôi đề nghị:ps aux | grep [h]ttpd
olibre

Tôi đã không sử dụng thủ thuật dấu ngoặc vuông ở đây để giúp dễ dàng đặt một biến vào chính grep.
Johnsyweb

1
Được rồi;) Tôi vừa thử nghiệm trên Red Hat AS 4 và Red Hat AP 5. Tất nhiên là tôi làm việc! Vì vậy, bạn có thể thêm vào danh sách của mình: Red Hat Enterprise Linux ES bản phát hành 4Red Hat Enterprise Linux Server bản phát hành 5 . Chúc mừng
olibre

@Downvoter: Tại sao? Tôi đã bỏ lỡ cái gì? Theo như tôi có thể nói, câu trả lời được chấp nhận đang thực hiện tra cứu tương tự!
Johnsyweb

6

Cách đơn giản nhất là sử dụng ps và grep:

command="httpd"
running=`ps ax | grep -v grep | grep $command | wc -l`
if [ running -gt 0 ]; then
    echo "Command is running"
else
    echo "Command is not running"
fi

Nếu lệnh của bạn có một số đối số lệnh, thì bạn cũng có thể đặt thêm 'grep cmd_arg1' sau 'grep $ command' để lọc ra các quy trình có thể có khác mà bạn không quan tâm.

Ví dụ: chỉ cho tôi nếu có bất kỳ quy trình java nào với đối số được cung cấp:

-Djava.util.logging.config.file = logging.properties

đang chạy

ps ax | grep -v grep | grep java | grep java.util.logging.config.file=logging.properties | wc -l

2
Trên thực tế, sử dụng ps caxloại bỏ nhu cầu sử dụng grep -v. Vì vậy, ví dụ, bạn có thể sử dụng: ps cax | grep java > /dev/null || echo "Java not running".
Highway of Life

1
Có một sai lầm ở dòng thứ 3. vui lòng thay đổi "running" thành "$ running".
Lập trình viên

5

Chỉ là một bổ sung nhỏ: nếu bạn thêm -ccờ vào ps, bạn không cần phải xóa dòng chứa quá trình grep grep -vsau đó. I E

ps acux | grep cron

là tất cả những gì bạn cần nhập trên hệ thống bsd-ish (điều này bao gồm cả MacOSX) Bạn có thể bỏ -uđi nếu bạn cần ít thông tin hơn.

Trên một hệ thống mà di truyền của pslệnh gốc trỏ về SysV, bạn sẽ sử dụng

ps -e |grep cron

hoặc là

ps -el |grep cron 

cho một danh sách không chỉ có pid và tên tiến trình. Tất nhiên, bạn có thể chọn các trường cụ thể để in ra bằng cách sử dụng -o <field,field,...>tùy chọn.


Câu trả lời này là xách tay như thế nào? (Bạn nói rằng các hình thức khác nhau của lệnh ps nên được sử dụng trên các nền tảng khác nhau)
peterh

Thật không may, ps là một trong những công cụ có tập hợp các tùy chọn khác nhau cho cùng một kết quả tùy thuộc vào tổ tiên của chúng. Vì vậy, trừ khi bạn viết trình bao bọc của riêng bạn (lại không tương thích với bất kỳ thứ gì khác) xung quanh điều này, cách để đi sẽ là biết các dòng chính của di sản và điều chỉnh cho phù hợp. Nó khác khi bạn đang viết kịch bản - ở đó bạn sẽ sử dụng những điểm khác biệt này để xác định bạn đang ở nhánh nào và điều chỉnh hành vi của tập lệnh của bạn. Điểm mấu chốt: bạn sẽ cần biết cả hai. Ví dụ nổi tiếng: Tập lệnh "config" của Larry Wall. Câu nói nổi tiếng: Xin chúc mừng, bạn không chạy Eunice.
Tatjana Heuser

5

Kết hợp các đề xuất khác nhau lại với nhau, phiên bản rõ ràng nhất mà tôi có thể đưa ra (không có grep không đáng tin cậy kích hoạt các phần của từ) là:

kill -0 $(pidof mysql) 2> /dev/null || echo "Mysql ain't runnin' message/actions"

kill -0 không giết quá trình nhưng kiểm tra nếu nó tồn tại và sau đó trả về true, nếu bạn không có pidof trên hệ thống của mình, hãy lưu trữ pid khi bạn khởi chạy quá trình:

$ mysql &
$ echo $! > pid_stored

thì trong script:

kill -0 $(cat pid_stored) 2> /dev/null || echo "Mysql ain't runnin' message/actions"

3

Tôi sử dụng pgrep -l httpdnhưng không chắc nó có trên nền tảng nào ...
Ai có thể xác nhận trên OSX?


Cảm ơn @Johnsyweb. Bạn cũng có thể kiểm tra được pidofkhông? OK, bạn đã làm. Cảm ơn bạn. Vì vậy, chúng ta nên tìm một thứ gì đó khác hoạt động trên OSX ... Cơ bản của bạn ps|grepcó thể là giải pháp duy nhất ;-)
olibre

1

Bạn nên biết PID của quy trình của bạn.

Khi bạn khởi chạy nó, PID của nó sẽ được ghi lại trong $!biến. Lưu PID này vào một tệp.

Sau đó, bạn sẽ cần kiểm tra xem PID này có tương ứng với một quy trình đang chạy hay không. Đây là một tập lệnh sườn hoàn chỉnh:

FILE="/tmp/myapp.pid"

if [ -f $FILE ];
then
   PID=$(cat $FILE)
else
   PID=1
fi

ps -o pid= -p $PID
if [ $? -eq 0 ]; then
  echo "Process already running."  
else
  echo "Starting process."
  run_my_app &
  echo $! > $FILE
fi

Dựa trên câu trả lời của peterh. Mẹo để biết liệu một PID nhất định có đang chạy hay không là trong ps -o pid= -p $PIDhướng dẫn.


0

Cách tiếp cận này có thể được sử dụng trong trường hợp lệnh 'ps', 'pidof' và phần còn lại không khả dụng. Cá nhân tôi sử dụng procfs rất thường xuyên trong các công cụ / tập lệnh / chương trình của mình.

   egrep -m1  "mysqld$|httpd$" /proc/[0-9]*/status | cut -d'/' -f3

Giải thích nhỏ về những gì đang xảy ra:

  1. -m1 - dừng quá trình ở trận đấu đầu tiên
  2. "mysqld $ | httpd $" - grep sẽ khớp với các dòng kết thúc trên mysqld HOẶC httpd
  3. / proc / [0-9] * - bash sẽ khớp với dòng bắt đầu bằng bất kỳ số nào
  4. cắt - chỉ cần tách đầu ra bằng dấu phân cách '/' và trích xuất trường 3

0

Điều này in ra số lượng quy trình có tên cơ sở là "chromium-browser":

ps -e -o args= | awk 'BEGIN{c=0}{
 if(!match($1,/^\[.*\]$/)){sub(".*/","",$1)} # Do not strip process names enclosed by square brackets.
 if($1==cmd){c++}
}END{print c}' cmd="chromium-browser"

Nếu điều này in ra "0", quá trình này không chạy. Lệnh giả định đường dẫn tiến trình không chứa khoảng trắng. Tôi chưa thử nghiệm điều này với các quy trình bị treo hoặc quy trình zombie.

Thử nghiệm sử dụng gwaknhư awkthay thế trong Linux.

Đây là một giải pháp linh hoạt hơn với một số ví dụ sử dụng:

#!/bin/sh
isProcessRunning() {
if [ "${1-}" = "-q" ]; then
 local quiet=1;
 shift
else
 local quiet=0;
fi
ps -e -o pid,args= | awk 'BEGIN{status=1}{
 name=$2
 if(name !~ /^\[.*\]$/){sub(".*/","",name)} # strip dirname, if process name is not enclosed by square brackets.
 if(name==cmd){status=0; if(q){exit}else{print $0}}
}END{exit status}' cmd="$1" q=$quiet
}

process='chromium-browser'

printf "Process \"${process}\" is "
if isProcessRunning -q "$process" 
 then printf "running.\n"
 else printf "not running.\n"; fi

printf "Listing of matching processes (PID and process name with command line arguments):\n"
isProcessRunning "$process"

0

Đây là phiên bản của tôi. Đặc trưng:

  • kiểm tra tên chương trình chính xác (đối số đầu tiên của hàm). tìm kiếm "mysql" sẽ không khớp với việc chạy "mysqld"
  • tìm kiếm các đối số của chương trình (đối số thứ hai của hàm)

kịch bản:

#!/bin/bash

# $1 - cmd
# $2 - args
# return: 0 - no error, running; 1 - error, not running
function isRunning() {
    for i in $(pidof $1); do
        cat /proc/$i/cmdline | tr '\000' ' ' | grep -F -e "$2" 1>&2> /dev/null
        if [ $? -eq 0 ]; then
            return 0
        fi
    done
    return 1
}

isRunning java "-Djava.util.logging.config.file=logging.properties"
if [ $? -ne 0 ]; then
    echo "not running, starting..."
fi

0

Không có câu trả lời nào phù hợp với tôi, vì vậy câu trả lời của tôi:

process="$(pidof YOURPROCESSHERE|tr -d '\n')"
if [[ -z "${process// }" ]]; then
  echo "Process is not running."
else
  echo "Process is running."
fi

Giải trình:

|tr -d '\n'

Thao tác này loại bỏ ký tự xuống dòng được tạo bởi terminal. Phần còn lại có thể được giải thích bởi bài đăng này .


-1

Hàm shell sau đây, chỉ dựa trên các lệnh và tùy chọn tiêu chuẩn POSIX nên hoạt động trên hầu hết (nếu không có) hệ thống Unix và linux. :

isPidRunning() {
  cmd=`
    PATH=\`getconf PATH\` export PATH
    ps -e -o pid= -o comm= |
      awk '$2 ~ "^.*/'"$1"'$" || $2 ~ "^'"$1"'$" {print $1,$2}'
  `
  [ -n "$cmd" ] &&
    printf "%s is running\n%s\n\n" "$1" "$cmd" ||
    printf "%s is not running\n\n" $1
  [ -n "$cmd" ]
}

$ isPidRunning httpd
httpd is running
586 /usr/apache/bin/httpd
588 /usr/apache/bin/httpd

$ isPidRunning ksh
ksh is running
5230 ksh

$ isPidRunning bash
bash is not running

Lưu ý rằng nó sẽ bị nghẹt thở khi truyền tên lệnh "0]" đáng ngờ và cũng sẽ không xác định được các quy trình có khoảng trắng nhúng trong tên của chúng.

Cũng xin lưu ý rằng giải pháp được nhiều người ủng hộ và chấp nhận nhất yêu cầu các pstùy chọn không di động và sử dụng vô cớ một trình bao mặc dù phổ biến nhưng không được đảm bảo có mặt trên mọi máy Unix / Linux ( bash)


$ isPidRunning 0]bản in ví dụ "0] đang chạy 3 [ksoftirqd / 0] 8 [rcuop / 0] 17 [rcuos / 0] 26 [rcuob / 0] 34 [igration / 0] 35 [watchdog / 0]" tại đây.
jarno

Bạn cần thứ PATH đó để làm gì?
jarno

Tôi đã phát triển thêm giải pháp ở đây .
jarno

@jarno Cài đặt PATH là một yêu cầu để tập lệnh có thể di động. Nếu không, nó sẽ không thành công ít nhất trên Solaris 10 trở lên và có thể là các triển khai Unix khác.
jlliagre

1
@jarno Tôi có thể làm điều đó nhưng cũng sẽ cần lặp lại cài đặt PATH này cho awk. Lưu ý rằng tôi đã hoàn nguyên về cú pháp backtick cũ để có thể di động với các shell theo cú pháp trước POSIX.
jlliagre
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.