Comando Linux / Unix per determinare se il processo è in esecuzione?


97

Ho bisogno di un comando shell / bash indipendente dalla piattaforma (Linux / Unix | OSX) che determinerà se è in esecuzione un processo specifico. eg mysqld, httpd... Qual è il modo / comando più semplice per farlo?

Risposte:


168

Sebbene pidofe pgrepsiano ottimi strumenti per determinare cosa è in esecuzione, purtroppo non sono entrambi disponibili su alcuni sistemi operativi. Un sicuro errore sarebbe quello di utilizzare quanto segue:ps cax | grep command

L'output su Gentoo Linux:

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

L'output su 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)

Sia su Linux che su OS X, grep restituisce un codice di uscita quindi è facile verificare se il processo è stato trovato o meno:

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

Inoltre, se desideri l'elenco dei PID, potresti facilmente grep anche per quelli:

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

Il cui output è lo stesso su Linux e OS X:

3519 3521 3523 3524

L'output di quanto segue è una stringa vuota, rendendo questo approccio sicuro per i processi che non sono in esecuzione:

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

Questo approccio è adatto per scrivere un semplice test di stringa vuota, quindi anche iterare attraverso i PID scoperti.

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

Puoi testarlo salvandolo in un file (chiamato "running") con i permessi di esecuzione (chmod + x running) ed eseguendolo con un parametro: ./running "httpd"

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

AVVERTIMENTO!!!

Tieni presente che stai semplicemente analizzando l'output il ps axche significa che, come visto nell'output di Linux, non si tratta semplicemente di corrispondenze sui processi, ma anche sugli argomenti passati a quel programma. Consiglio vivamente di essere il più specifico possibile quando si utilizza questo metodo (ad esempio ./running "mysql", corrisponderà anche ai processi "mysqld"). Consiglio vivamente di utilizzare whichper confrontare un percorso completo, ove possibile.


Riferimenti:

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

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


Il processo può essere in esecuzione, ma interrotto. Quindi, se l'obiettivo è testare se mysqld o httpd sono "attivi e funzionanti" (rispondendo), dovresti anche controllare se sono fermi o meno.
oluc

2
Scusate, ma anche se la risposta è certamente giusta da un punto di vista semantico, sono completamente contrario a cercare un processo mediante il pattern matching sul vettore arg del processo. Qualsiasi approccio di questo tipo è destinato a fallire prima o poi (in realtà lo ammetti tu stesso, dicendo che sono necessari ulteriori controlli). Ho aggiunto la mia raccomandazione in una risposta separata.
Peterh

6
grepsi troverà anche in esecuzione (ad es. ps cax | grep randomnamerestituirà sempre 0 perché greptrova grep randomname(spero sia chiaro ...). Una soluzione è aggiungere parentesi quadre attorno alla prima lettera del nome del processo, ad es ps cax | grep [r]andomname.
Kyle G.

ps cax | rev | cut -f1 -d' ' | revmostrerà solo la colonna del nome, per un'analisi più semplice.
Tyzoid

1
ps caxpotrebbe non produrre interamente il nome del comando. Ad esempio, stampa "chrome-browse" invece di "chrome-browser".
jarno

24

DOVRESTI conoscere il PID!

Trovare un processo provando a fare una sorta di riconoscimento di pattern sugli argomenti del processo (come pgrep "mysqld") è una strategia destinata a fallire prima o poi. E se hai due mysqld in esecuzione? Dimentica quell'approccio. Potresti farlo bene temporaneamente e POTREBBE funzionare per un anno o due, ma poi succede qualcosa a cui non hai pensato.

Solo l'id del processo (pid) è veramente unico.

Memorizza sempre il pid quando avvii qualcosa in background. In Bash questo può essere fatto con la $!variabile Bash. Ti risparmierai così tanti problemi in questo modo.

Come determinare se il processo è in esecuzione (tramite pid)

Quindi ora la domanda diventa come sapere se un pid è in esecuzione.

Basta fare:

ps -o pid = -p <pid>

Questo è POSIX e quindi portabile. Restituirà il pid stesso se il processo è in esecuzione o non restituirà nulla se il processo non è in esecuzione. A rigor di termini il comando restituirà una singola colonna, la pid, ma poiché abbiamo dato un'intestazione del titolo vuota (la roba immediatamente precedente il segno di uguale) e questa è l'unica colonna richiesta, il comando ps non utilizzerà affatto l'intestazione. Che è quello che vogliamo perché rende più facile l'analisi.

Funzionerà su Linux, BSD, Solaris, ecc.

Un'altra strategia potrebbe essere quella di testare il valore di uscita dal pscomando precedente . Dovrebbe essere zero se il processo è in esecuzione e diverso da zero se non lo è. La specifica POSIX dice che psdeve uscire> 0 se si è verificato un errore, ma non mi è chiaro cosa costituisca "un errore". Pertanto non sto usando personalmente quella strategia, anche se sono abbastanza sicuro che funzionerà anche su tutte le piattaforme Unix / Linux.


1
Tranne che questo non risponde alla domanda, che è determinare se un servizio è in esecuzione. Il PID non sarà conosciuto in questi casi, quindi, questa risposta è valida solo se si fa conoscere il PID.
Highway of Life

2
Sbagliato. Il punto centrale del commento è fare un passo indietro e dire che se prima ti trovi nella situazione in cui devi fare una qualche forma grep <sometext>per trovare un determinato processo, allora hai fatto qualcosa di sbagliato quando hai iniziato il processo, IMHO. Dalla domanda del PO deduco che egli abbia effettivamente il controllo su come viene avviato il processo.
Peterh

2
Il "termine" più corretto per la domanda OP avrebbe dovuto essere "comando multipiattaforma per determinare se un servizio è in esecuzione", non è lo stesso sistema che esegue il controllo, ma un sistema esterno, quindi il PID non sarà noto a tutti.
Highway of Life

2
Questo non è infallibile. Il processo a cui sei interessato potrebbe essere terminato dopo che il sistema è stato attivato abbastanza a lungo da consentire il completamento dei PID e un altro processo potrebbe essere stato assegnato allo stesso PID che stai verificando. stackoverflow.com/questions/11323410/linux-pid-recycling
claymation

1
@claymation. Punto valido. Tuttavia, il metodo PID è ancora migliore della corrispondenza del modello sugli argomenti di processo poiché l'interferenza PID è molto più improbabile rispetto all'avvio accidentale di due istanze dello stesso servizio. Solo i miei due centesimi. :-)
peterh

15

Sulla maggior parte delle distribuzioni Linux, puoi usare pidof(8).

Stamperà gli ID di processo di tutte le istanze in esecuzione di processi specificati o nulla se non ci sono istanze in esecuzione.

Ad esempio, sul mio sistema (ho quattro istanze di bashe un'istanza di remminaesecuzione):

$ pidof bash remmina
6148 6147 6144 5603 21598

Su altri Unices, pgrepo una combinazione di pse grepotterrà lo stesso risultato, come altri hanno giustamente sottolineato.


+1 pidof httpdfunziona bene su Red Hat 5. Ma sul mio Red Hat 4 pidofnon è presente :-(
olibre

In effetti, questo comando è meno diffuso di quanto pensassi, ho modificato la mia risposta per renderlo più chiaro.
Frédéric Hamidi

Bella risposta pulita davvero. (sui sistemi supportati). Grazie.
Mtl Dev

7

Questo dovrebbe funzionare sulla maggior parte delle versioni di Unix, BSD e Linux:

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

Testato su:

  • SunOS 5.10 [Da qui il PATH=...]
  • Linux 2.6.32 (CentOS)
  • Linux 3.0.0 (Ubuntu)
  • Darwin 11.2.0
  • FreeBSD 9.0-STABILE
  • Red Hat Enterprise Linux ES versione 4
  • Red Hat Enterprise Linux Server versione 5

2
+1 Sì semplicemente ps. Per evitare la seconda grepconsiglio:ps aux | grep [h]ttpd
olibre

Non ho usato il trucco delle parentesi quadre qui per rendere più facile l'inserimento di una variabile nel main grep.
Johnsyweb

1
Va bene;) Ho appena provato Red Hat AS 4 e Red Hat AP 5. Certo che funziona! Quindi puoi aggiungere alla tua lista: Red Hat Enterprise Linux ES release 4 e Red Hat Enterprise Linux Server release 5 . Saluti
olibre

@Downvoter: perché? Cosa mi sono perso? Per quanto ne so, la risposta accettata sta facendo la stessa ricerca!
Johnsyweb

6

Il modo più semplice è usare ps e 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

Se il tuo comando ha alcuni argomenti di comando, puoi anche inserire più 'grep cmd_arg1' dopo 'grep $ command' per filtrare altri possibili processi a cui non sei interessato.

Esempio: mostrami se un processo java con argomento fornito:

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

è in esecuzione

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

2
In realtà, l'utilizzo ps caxelimina la necessità di utilizzare grep -v. Così, per esempio, è possibile utilizzare: ps cax | grep java > /dev/null || echo "Java not running".
Highway of Life,

1
C'è un errore nella 3a riga. si prega di cambiare "running" in "$ running".
Programmatore

5

Solo una piccola aggiunta: se aggiungi il -cflag a ps, non è necessario rimuovere la riga contenente il processo grep con in grep -vseguito. Cioè

ps acux | grep cron

è tutto ciò di cui hai bisogno su un sistema bsd-ish (questo include MacOSX) Puoi lasciare il campo -use hai bisogno di meno informazioni.

Su un sistema in cui la genetica del pscomando nativo rimanda a SysV, useresti

ps -e |grep cron

o

ps -el |grep cron 

per un elenco contenente più del solo pid e nome del processo. Ovviamente puoi selezionare i campi specifici da stampare utilizzando l' -o <field,field,...>opzione.


In che modo questa risposta è portatile? (Dici che diverse forme del comando ps dovrebbero essere utilizzate su piattaforme diverse)
Peterh

ps purtroppo è uno di quegli strumenti con un diverso insieme di opzioni per lo stesso risultato a seconda della loro ascendenza. Quindi, a meno che tu non scriva il tuo involucro (di nuovo incompatibile con qualsiasi altra cosa) attorno a questo, la strada da percorrere sarebbe conoscere le linee principali del patrimonio e adattarti di conseguenza. È diverso quando scrivi: qui useresti queste differenze per determinare in quale ramo ti trovi e adattare il comportamento del tuo script. In conclusione: dovrai conoscerli entrambi. Esempio famoso: lo script "configure" di Larry Wall. Citazione famosa: Congratulazioni, non gestisci Eunice.
Tatjana Heuser

5

Mettendo insieme i vari suggerimenti, la versione più pulita che sono riuscito a trovare (senza grep inaffidabile che innesca parti di parole) è:

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

kill -0 non uccide il processo ma controlla se esiste e poi restituisce true, se non hai pidof sul tuo sistema, memorizza il pid quando avvii il processo:

$ mysql &
$ echo $! > pid_stored

poi nello script:

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

3

Lo uso pgrep -l httpdma non sono sicuro che sia presente su qualsiasi piattaforma ...
Chi può confermare su OSX?


Grazie @Johnsyweb. Puoi anche controllare per pidoffavore? OK l'hai fatto. Grazie. Quindi dovremmo trovare qualcos'altro che funzioni su OSX ... La tua base ps|greppotrebbe essere l'unica soluzione ;-)
olibre

1

Dovresti conoscere il PID del tuo processo.

Quando lo avvii, il suo PID verrà registrato nella $!variabile. Salva questo PID in un file.

Quindi sarà necessario verificare se questo PID corrisponde a un processo in esecuzione. Ecco uno script completo dello scheletro:

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

Basato sulla risposta di peterh. Il trucco per sapere se un dato PID è in esecuzione è ps -o pid= -p $PIDnell'istruzione.


0

Questo approccio può essere utilizzato nel caso in cui i comandi "ps", "pidof" e rest non siano disponibili. Personalmente uso procfs molto frequentemente nei miei strumenti / script / programmi.

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

Piccola spiegazione di cosa sta succedendo:

  1. -m1 - interrompe il processo alla prima partita
  2. "mysqld $ | httpd $" - grep corrisponderà alle righe che terminano in mysqld OR httpd
  3. / proc / [0-9] * - bash corrisponderà alla riga che inizia con qualsiasi numero
  4. cut - basta dividere l'output con il delimitatore '/' ed estrarre il campo 3

0

Questo stampa il numero di processi il cui nome di base è "chrome-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"

Se viene stampato "0", il processo non è in esecuzione. Il comando presuppone che il percorso del processo non contenga spazi di interruzione. Non l'ho testato con processi sospesi o processi zombie.

Testato utilizzando gwakcome awkalternativa in Linux.

Ecco una soluzione più versatile con alcuni esempi di utilizzo:

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

Ecco la mia versione. Caratteristiche:

  • controlla il nome esatto del programma (primo argomento della funzione). la ricerca di "mysql" non corrisponderà all'esecuzione di "mysqld"
  • cerca gli argomenti del programma (secondo argomento della funzione)

script:

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

Nessuna delle risposte ha funzionato per me, quindi ecco la mia:

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

Spiegazione:

|tr -d '\n'

Questo rimuove il ritorno a capo creato dal terminale. Il resto può essere spiegato da questo post.


-1

La seguente funzione di shell, essendo basata solo su comandi e opzioni standard POSIX, dovrebbe funzionare sulla maggior parte dei sistemi Unix e Linux (se non ce ne sono). :

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

Notare che si strozzerà quando verrà passato il dubbio nome del comando "0]" e non riuscirà nemmeno a identificare i processi che hanno uno spazio incorporato nei loro nomi.

Nota anche che la soluzione più votata e accettata richiede psopzioni non portabili e utilizza gratuitamente una shell che, nonostante la sua popolarità, non è garantita essere presente su ogni macchina Unix / Linux ( bash)


$ isPidRunning 0]stampa ad esempio "0] è in esecuzione 3 [ksoftirqd / 0] 8 [rcuop / 0] 17 [rcuos / 0] 26 [rcuob / 0] 34 [migration / 0] 35 [watchdog / 0]" qui.
jarno

A cosa ti serve quella cosa PATH?
jarno

Ho sviluppato ulteriormente la soluzione qui .
jarno

@jarno L'impostazione PATH è un requisito per la portabilità dello script. Altrimenti, fallirebbe almeno su Solaris 10 e versioni precedenti e forse su altre implementazioni Unix.
jlliagre

1
@jarno Potrei farlo ma dovrò ripetere questa impostazione PATH anche per awk. Si noti che sono tornato alla vecchia sintassi backtick per essere portabile con le shell bourne di sintassi pre-POSIX.
jlliagre
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.