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?
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:
Sebbene pidof
e pgrep
siano 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 ax
che 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 which
per confrontare un percorso completo, ove possibile.
Riferimenti:
grep
si troverà anche in esecuzione (ad es. ps cax | grep randomname
restituirà sempre 0 perché grep
trova 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
.
ps cax | rev | cut -f1 -d' ' | rev
mostrerà solo la colonna del nome, per un'analisi più semplice.
ps cax
potrebbe non produrre interamente il nome del comando. Ad esempio, stampa "chrome-browse" invece di "chrome-browser".
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.
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 ps
comando precedente . Dovrebbe essere zero se il processo è in esecuzione e diverso da zero se non lo è. La specifica POSIX dice che ps
deve 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.
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.
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 bash
e un'istanza di remmina
esecuzione):
$ pidof bash remmina
6148 6147 6144 5603 21598
Su altri Unices, pgrep
o una combinazione di ps
e grep
otterrà lo stesso risultato, come altri hanno giustamente sottolineato.
pidof httpd
funziona bene su Red Hat 5. Ma sul mio Red Hat 4 pidof
non è presente :-(
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:
PATH=...
]ps
. Per evitare la seconda grep
consiglio:ps aux | grep [h]ttpd
grep
.
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
ps cax
elimina la necessità di utilizzare grep -v
. Così, per esempio, è possibile utilizzare: ps cax | grep java > /dev/null || echo "Java not running"
.
Solo una piccola aggiunta: se aggiungi il -c
flag a ps, non è necessario rimuovere la riga contenente il processo grep con in grep -v
seguito. Cioè
ps acux | grep cron
è tutto ciò di cui hai bisogno su un sistema bsd-ish (questo include MacOSX) Puoi lasciare il campo -u
se hai bisogno di meno informazioni.
Su un sistema in cui la genetica del ps
comando 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.
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"
Lo uso pgrep -l httpd
ma non sono sicuro che sia presente su qualsiasi piattaforma ...
Chi può confermare su OSX?
pidof
favore? OK l'hai fatto. Grazie. Quindi dovremmo trovare qualcos'altro che funzioni su OSX ... La tua base ps|grep
potrebbe essere l'unica soluzione ;-)
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 $PID
nell'istruzione.
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:
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 gwak
come awk
alternativa 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"
Ecco la mia versione. Caratteristiche:
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
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.
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 ps
opzioni 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.