Polecenie Linux / Unix, aby określić, czy proces jest uruchomiony?

97

Potrzebuję niezależnego od platformy polecenia powłoki / bash (Linux / Unix | OSX), które określi, czy jest uruchomiony określony proces. na przykład mysqld, httpd... Co to jest najprostszym sposobem / command to zrobić?

Autostrada życia
źródło

Odpowiedzi:

168

Chociaż pidofi pgrepsą świetnymi narzędziami do określania, co jest uruchomione, oba są niestety niedostępne w niektórych systemach operacyjnych. Zdecydowanym zabezpieczeniem przed awarią byłoby użycie następującego:ps cax | grep command

Dane wyjściowe w Gentoo Linux:

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

Wyjście na 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)

Zarówno w systemie Linux, jak i OS X, grep zwraca kod zakończenia, więc łatwo jest sprawdzić, czy proces został znaleziony, czy nie:

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

Ponadto, jeśli chciałbyś zobaczyć listę PIDów, możesz łatwo grepować również dla nich:

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

Czyje dane wyjściowe są takie same w systemie Linux i OS X:

3519 3521 3523 3524

Dane wyjściowe to pusty ciąg, dzięki czemu to podejście jest bezpieczne dla procesów, które nie są uruchomione:

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

To podejście jest odpowiednie do napisania prostego testu pustego łańcucha, a następnie nawet iteracji przez odkryte PIDy.

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

Możesz to przetestować zapisując go do pliku (o nazwie „działa”) z uprawnieniami do wykonywania (chmod + x działa) i uruchamiając go z parametrem: ./running "httpd"

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

OSTRZEŻENIE!!!

Należy pamiętać, że po prostu analizujesz dane wyjściowe, ps axco oznacza, że, jak widać na wyjściu Linuksa, nie jest ono po prostu dopasowywane do procesów, ale także do argumentów przekazanych do tego programu. Zdecydowanie zalecam bycie jak najbardziej szczegółowym podczas korzystania z tej metody (np. ./running "mysql"Dopasuje również procesy 'mysqld'). Gorąco polecam korzystanie whichz pełnej ścieżki, jeśli to możliwe.


Bibliografia:

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

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

Caleb Gray
źródło
Proces może być uruchomiony, ale został zatrzymany. Jeśli więc celem jest sprawdzenie, czy mysqld lub httpd są „uruchomione” (odpowiadają), należy również sprawdzić, czy jest zatrzymane, czy nie.
oluc
2
Przepraszam, ale chociaż odpowiedź jest z pewnością właściwa z semantycznego punktu widzenia, jestem całkowicie przeciwny szukaniu procesu przez dopasowanie wzorców w wektorze arg procesu. Każde takie podejście prędzej czy później skazane jest na niepowodzenie (sam przyznajesz się do tego, mówiąc, że potrzeba więcej kontroli). Dodałem własną rekomendację w osobnej odpowiedzi.
peterh
6
grepbędzie również znaleźć się pracuje (np ps cax | grep randomnamezawsze zwraca 0, ponieważ grepznaleziska grep randomname(nadzieję, że to jest jasne ...) Jedna poprawka jest dodanie nawiasów kwadratowych wokół pierwszej litery nazwy procesów, np. ps cax | grep [r]andomname.
Kyle'owi G.
ps cax | rev | cut -f1 -d' ' | revpokaże tylko kolumnę z nazwą, aby ułatwić analizowanie.
Tyzoid
1
ps caxmoże nie wyświetlać całej nazwy polecenia. Np. Drukuje "przeglądarka chromu" zamiast "przeglądarka chromu".
jarno
24

POWINIENEŚ znać PID!

Znalezienie procesu poprzez próbę rozpoznania wzorców w argumentach procesu (takich jak pgrep "mysqld") to strategia, która prędzej czy później jest skazana na niepowodzenie. A co jeśli masz dwa uruchomione mysqld? Zapomnij o takim podejściu. MOŻESZ to naprawić chwilowo i MOŻE działać przez rok lub dwa, ale potem dzieje się coś, o czym nie myślałeś.

Jedynie identyfikator procesu (pid) jest naprawdę wyjątkowy.

Zawsze przechowuj pid, gdy uruchamiasz coś w tle. W Bash można to zrobić za pomocą $!zmiennej Bash. Oszczędzisz sobie w ten sposób TAKI kłopotów.

Jak ustalić, czy proces jest uruchomiony (przez pid)

Teraz pojawia się pytanie, jak sprawdzić, czy pid jest uruchomiony.

Po prostu zrób:

ps -o pid = -p <pid>

To jest POSIX i stąd przenośne. Zwróci sam pid, jeśli proces jest uruchomiony, lub nic nie zwróci, jeśli proces nie jest uruchomiony. Ściśle mówiąc, polecenie zwróci pojedynczą kolumnę, the pid, ale ponieważ podaliśmy pusty nagłówek tytułu (element bezpośrednio poprzedzający znak równości) i jest to jedyna żądana kolumna, polecenie ps w ogóle nie użyje nagłówka. Właśnie tego chcemy, ponieważ ułatwia to analizowanie.

To zadziała na Linuksie, BSD, Solarisie itp.

Inną strategią byłoby przetestowanie wartości wyjścia z powyższego pspolecenia. Powinno wynosić zero, jeśli proces jest uruchomiony i niezerowe, jeśli nie. Specyfikacja POSIX mówi, że psmusi zakończyć się> 0, jeśli wystąpił błąd, ale nie jest dla mnie jasne, co stanowi „błąd”. Dlatego osobiście nie używam tej strategii, chociaż jestem prawie pewien, że zadziała ona również na wszystkich platformach Unix / Linux.

peterh
źródło
1
Tyle że to nie odpowiada na pytanie, które polega na ustaleniu, czy usługa jest uruchomiona. W takich przypadkach PID nie będzie znany, dlatego ta odpowiedź jest ważna tylko wtedy, gdy znasz PID.
Highway of Life,
2
Źle. Cały mój komentarz polega na tym, aby cofnąć się o krok i powiedzieć, że jeśli najpierw znajdziesz się w sytuacji, w której musisz wykonać jakąś formę, grep <sometext>aby znaleźć dany proces, to zrobiłeś coś złego, kiedy zacząłeś proces, IMHO. Wychodzę z pytania PO, że rzeczywiście ma kontrolę nad tym, jak rozpoczyna się ten proces.
peterh
2
Bardziej poprawnym „terminem” dla pytania OP powinno być „polecenie międzyplatformowe w celu określenia, czy usługa jest uruchomiona”, to nie ten sam system, na którym działa sprawdzanie, ale system zewnętrzny, więc PID po prostu nie będzie w ogóle znany.
Highway of Life,
2
To nie jest niezawodne. Proces, który Cię interesuje, mógł zgasnąć po tym, jak system działał wystarczająco długo, aby PIDy mogły się zawinąć, a inny proces mógł otrzymać ten sam PID, którego szukasz. stackoverflow.com/questions/11323410/linux-pid-recycling
claymation
1
@claymation. Słuszna uwaga. Jednak metoda PID jest nadal lepsza niż dopasowywanie wzorców w argumentach procesu, ponieważ zderzenie PID jest znacznie mniej prawdopodobne niż powiedzmy przypadkowe uruchomienie dwóch wystąpień tej samej usługi. Tylko moje dwa centy. :-)
peterh
15

W większości dystrybucji Linuksa możesz użyć pidof(8).

Wyświetli identyfikatory procesów wszystkich uruchomionych instancji określonych procesów lub nic, jeśli nie ma uruchomionych instancji.

Na przykład w moim systemie (mam cztery wystąpienia bashi jedną remminauruchomioną):

$ pidof bash remmina
6148 6147 6144 5603 21598

Na innych Unikach pgreplub połączenie psi greposiągnie to samo, jak słusznie wskazali inni.

Frédéric Hamidi
źródło
+1 pidof httpddziała dobrze na Red Hat 5. Ale na moim Red Hat 4 pidofnie jest obecny :-(
olibre
Rzeczywiście, to polecenie jest mniej rozpowszechnione niż myślałem, zredagowałem odpowiedź, aby było jaśniejsze.
Frédéric Hamidi
Naprawdę ładna, czysta odpowiedź. (w obsługiwanych systemach). Dziękuję Ci.
Mtl Dev
7

Powinno to działać na większości odmian Uniksa, BSD i Linuksa:

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

Przetestowano na:

  • SunOS 5.10 [Stąd PATH=...]
  • Linux 2.6.32 (CentOS)
  • Linux 3.0.0 (Ubuntu)
  • Darwin 11.2.0
  • FreeBSD 9.0-STABILNY
  • Red Hat Enterprise Linux ES wersja 4
  • Red Hat Enterprise Linux Server w wersji 5
Johnsyweb
źródło
2
+1 Tak, po prostu ps. Aby uniknąć drugiego grep, proponuję:ps aux | grep [h]ttpd
olibre
Nie użyłem tutaj sztuczki z nawiasami kwadratowymi, aby ułatwić umieszczenie zmiennej w main grep.
Johnsyweb
1
Dobra;) Właśnie przetestowałem Red Hat AS 4 i Red Hat AP 5. Oczywiście, że działa! Możesz więc dodać do swojej listy: Red Hat Enterprise Linux ES wersja 4 i Red Hat Enterprise Linux Server wersja 5 . Pozdrawiam
olibre
@Downvoter: Dlaczego? Co mnie ominęło? O ile wiem, zaakceptowaną odpowiedzią jest wykonanie tego samego wyszukiwania!
Johnsyweb
6

Najprostszym sposobem jest użycie ps i 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

Jeśli twoje polecenie ma jakieś argumenty poleceń, możesz również wstawić więcej „grep cmd_arg1” po „grep $ command”, aby odfiltrować inne możliwe procesy, którymi nie jesteś zainteresowany.

Przykład: pokaż mi, czy jakikolwiek proces java z podanym argumentem:

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

biegnie

ps ax | grep -v grep | grep java | grep java.util.logging.config.file=logging.properties | wc -l
Paweł Solarski
źródło
2
Właściwie używanie ps caxeliminuje potrzebę używania grep -v. Tak na przykład, można użyć: ps cax | grep java > /dev/null || echo "Java not running".
Highway of Life
1
W trzeciej linii jest błąd. zmień „działa” na „$ działa”.
Programmer
5

Tylko drobny dodatek: jeśli dodasz -cflagę do ps, nie musisz później usuwać wiersza zawierającego proces grep grep -v. To znaczy

ps acux | grep cron

to wszystko, czego potrzebujesz w systemie bsd-ish (w tym MacOSX). -uJeśli potrzebujesz mniej informacji, możesz zostawić go daleko.

W systemie, w którym genetyka natywnego pspolecenia wskazuje na SysV, użyłbyś

ps -e |grep cron

lub

ps -el |grep cron 

dla listy zawierającej więcej niż tylko pid i nazwę procesu. Oczywiście możesz wybrać określone pola do wydrukowania za pomocą -o <field,field,...>opcji.

Tatjana Heuser
źródło
W jaki sposób ta odpowiedź jest przenośna? (Mówisz, że różne formy polecenia ps powinny być używane na różnych platformach)
peterh
ps niestety jest jednym z tych narzędzi z innym zestawem opcji dla tego samego wyniku w zależności od ich pochodzenia. Tak więc, o ile nie napiszesz własnego (ponownie niekompatybilnego z niczym innym) opakowania wokół tego, sposobem byłoby poznanie głównych linii dziedzictwa i odpowiednie dostosowanie. Jest inaczej, gdy tworzysz skrypty - tam możesz użyć tych różnic, aby określić, w której gałęzi się znajdujesz i dostosować zachowanie swojego skryptu. Konkluzja: musisz znać oba. Słynny przykład: skrypt „konfiguruj” Larry'ego Wall'a. Słynny cytat: Gratulacje, nie prowadzisz Eunice.
Tatjana Heuser
5

Łącząc różne sugestie, najczystsza wersja, jaką udało mi się wymyślić (bez niewiarygodnego grepa, który uruchamia części słów) to:

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

kill -0 nie zabija procesu, ale sprawdza, czy istnieje, a następnie zwraca prawdę, jeśli nie masz pidof w systemie, zapisz pid podczas uruchamiania procesu:

$ mysql &
$ echo $! > pid_stored

następnie w skrypcie:

kill -0 $(cat pid_stored) 2> /dev/null || echo "Mysql ain't runnin' message/actions"
gletscher
źródło
3

Używam, pgrep -l httpdale nie jestem pewien, czy jest obecny na dowolnej platformie ...
Kto może potwierdzić na OSX?

olibre
źródło
Dzięki @Johnsyweb. Czy możesz też sprawdzić pidof? OK, zrobiłeś. Dziękuję Ci. Powinniśmy więc znaleźć coś innego działającego na OSX ... Twoim podstawowym rozwiązaniem ps|grepmoże być jedno rozwiązanie ;-)
olibre
1

Powinieneś znać PID swojego procesu.

Kiedy go uruchomisz, jego PID zostanie zapisany w $!zmiennej. Zapisz ten PID do pliku.

Następnie musisz sprawdzić, czy ten PID odpowiada działającemu procesowi. Oto kompletny szkielet skryptu:

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

W oparciu o odpowiedzi na peterh. Sztuczka pozwalająca dowiedzieć się, czy dany PID działa, znajduje się w ps -o pid= -p $PIDinstrukcji.

icarito
źródło
0

To podejście można zastosować w przypadku, gdy polecenia „ps”, „pidof” i rest nie są dostępne. Osobiście bardzo często używam procfs w moich narzędziach / skryptach / programach.

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

Małe wyjaśnienie, co się dzieje:

  1. -m1 - zatrzymaj proces przy pierwszym dopasowaniu
  2. "mysqld $ | httpd $" - grep dopasuje wiersze zakończone na mysqld LUB httpd
  3. / proc / [0-9] * - bash dopasuje linię zaczynającą się od dowolnej liczby
  4. cut - po prostu podziel wynik za pomocą separatora „/” i wyodrębnij pole 3
Tom Lime
źródło
0

Wypisuje liczbę procesów, których podstawową nazwą jest „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"

Jeśli wypisze "0", proces nie jest uruchomiony. Polecenie zakłada, że ​​ścieżka procesu nie zawiera spacji. Nie testowałem tego z zawieszonymi procesami lub procesami zombie.

Przetestowano gwakjako awkalternatywę w systemie Linux.

Oto bardziej wszechstronne rozwiązanie z przykładowym zastosowaniem:

#!/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"
jarno
źródło
0

Oto moja wersja. Cechy:

  • sprawdza dokładną nazwę programu (pierwszy argument funkcji). wyszukiwanie „mysql” nie będzie pasować do działającego „mysqld”
  • wyszukuje argumenty programu (drugi argument funkcji)

scenariusz:

#!/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
Raigedas
źródło
0

Żadna z odpowiedzi nie zadziałała dla mnie, więc oto moja:

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

Wyjaśnienie:

|tr -d '\n'

To usuwa znak powrotu karetki utworzony przez terminal. Resztę można wyjaśnić w tym poście.

Jeff Luyet
źródło
-1

Następująca funkcja powłoki, oparta tylko na standardowych poleceniach i opcjach POSIX, powinna działać w większości (jeśli nie na żadnym) systemach Unix i 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

Zauważ, że dusi się po przekazaniu wątpliwej nazwy polecenia „0]”, a także nie będzie w stanie zidentyfikować procesów mających w nazwie spację.

Zauważ również, że najbardziej popularne i akceptowane rozwiązanie wymaga psopcji nieprzenośnych i nieodpłatnie korzysta z powłoki, która pomimo swojej popularności nie ma gwarancji, że będzie obecna na każdej maszynie z systemem Unix / Linux ( bash)

jlliagre
źródło
$ isPidRunning 0]wyświetla np. „0] działa 3 [ksoftirqd / 0] 8 [rcuop / 0] 17 [rcuos / 0] 26 [rcuob / 0] 34 [migracja / 0] 35 [watchdog / 0]”.
jarno
Po co ci ta PATH?
jarno
Tutaj rozwinąłem rozwiązanie dalej .
jarno
@jarno Ustawienie PATH jest wymagane, aby skrypt był przenośny. W przeciwnym razie nie powiedzie się przynajmniej na Solaris 10 i starszych oraz prawdopodobnie innych implementacjach Uniksa.
jlliagre
1
@jarno Mogę to zrobić, ale będę musiał powtórzyć to ustawienie PATH również dla awk. Zauważ, że powróciłem do starej składni backtick, aby być przenośnym z powłokami bourne pre-POSIX.
jlliagre