Cómo verificar si existe una identificación de proceso (PID)

184

En un script bash, quiero hacer lo siguiente (en pseudocódigo):

if [ a process exists with $PID ]; then

    kill $PID 

fi

¿Cuál es la expresión apropiada para la declaración condicional?

Richard H
fuente

Respuestas:

182

Para verificar la existencia de un proceso, use

kill -0 $pid

Pero justo como dijo @unwind, si vas a matarlo de todos modos, solo

kill $pid

o tendrás una condición de carrera.

Si desea ignorar la salida de texto killy hacer algo basado en el código de salida, puede

if ! kill $pid > /dev/null 2>&1; then
    echo "Could not send SIGTERM to process $pid" >&2
fi
Christoffer Hammarström
fuente
1
mirando la página del manual, kill -0 es: "el código de salida indica si se puede enviar una señal". Entonces, ¿esto realmente mata un proceso, o simplemente te dice si se puede matar?
Richard H
24
killtiene un nombre erróneo porque no necesariamente mata el proceso. Simplemente envía una señal al proceso. kill $PIDes equivalente a kill -15 $PID, que envía la señal 15, SIGTERM al proceso, que es una instrucción para finalizar. No hay una señal 0, ese es un valor especial que indica killque solo se verifique si se puede enviar una señal al proceso, que para la mayoría de los propósitos es más o menos equivalente a verificar si existe. Ver linux.die.net/man/2/kill y linux.die.net/man/7/signal
Christoffer Hammarström
43
Esto tiene el problema de que si el proceso no es propiedad del usuario en ejecución, es posible que no tenga permisos para llamar a kill -0. Es mejor usar ps -p $ PID> / dev / null 2> & 1, que le permite ver el estado del proceso, incluso si no tiene permisos para enviar una señal.
mckoss 01 de
66
@mckoss: En ese caso, no puede matarlo de todos modos.
Christoffer Hammarström
2
Entonces, supongo que, para usarlo kill -0, de hecho, tengo que hacer esto: kill -0 25667 ; echo $?- y luego, si recibo una 0devolución, entonces el proceso con ese PID puede cancelarse; y si el PID del proceso (por ejemplo) no existe, lo $?será 1, lo que indica un error. ¿Es eso correcto?
sdaau
264

La mejor manera es:

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

El problema con:

kill -0 $PID

es que el código de salida no será cero, incluso si el pid se está ejecutando y no tiene permiso para eliminarlo. Por ejemplo:

kill -0 1

y

kill -0 $non-running-pid

tener un código de salida indistinguible (no cero) para un usuario normal, pero el proceso de inicio (PID 1) ciertamente se está ejecutando.

DISCUSIÓN

Las respuestas sobre las condiciones de muerte y carrera son exactamente correctas si el cuerpo de la prueba es una "muerte". Vine buscando el general " ¿cómo se prueba una existencia de PID en bash "?

El método / proc es interesante, pero en cierto sentido rompe el espíritu de la abstracción del comando "ps", es decir, no necesita buscar en / proc porque ¿qué pasa si Linus decide llamar al archivo "exe" de otra manera?

FDS
fuente
1
ps -p siempre me devuelve el estado 0
IttayD
1
ps -p #### funcionó bien para mí en Ubuntu 14.04, +1 ¡gracias!
Ligemer
3
ps -p siempre devuelve el código de estado 0 en os x porque imprime una lista vacía de proceso cuando no coincide con ningún proceso en ejecución
Douglas Correa
Puedo confirmar que en macOS Sierra, esto funciona. Además, -pes innecesario, al menos en ese caso. ps $PIDtiene exactamente el mismo resultado.
user137369
La portabilidad es una buena razón para evitar el uso de / proc, pero Linux que rompa su ABI no es un escenario que me preocupe particularmente.
David Roundy
67
if [ -n "$PID" -a -e /proc/$PID ]; then
    echo "process exists"
fi

o

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

En la última forma, -o pid=es un formato de salida para mostrar solo la columna de ID de proceso sin encabezado. Las comillas son necesarias para que el operador de cadena no vacía -ndé un resultado válido.

usuario2683246
fuente
1
El segundo método también funciona en Mac, como una ventaja adicional (Mac OS X no tiene / proc FS). Sin embargo, puede evitar usar un subshell y usarlo tanto en Mac como en Linux:if ps -p"$PID" -o "pid=" >/dev/null 2>&1; then echo "Process is running..."; fi
Será el
Desafortunadamente, las psopciones y características tienden a variar entre plataformas, por lo que aún no es completamente portátil.
tripleee
1
si $PIDestá vacío [ -e /proc/$PID ], aún devolverá verdadero, ya que el /proc/directorio todavía existe.
Magne
34

pscomando con -p $PIDpuede hacer esto:

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

Tienes dos formas:

Comencemos buscando una aplicación específica en mi computadora portátil:

[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

Todos los ejemplos buscarán ahora el PID 3358.

Primera forma : Ejecute "ps aux" y grep para el PID en la segunda columna. En este ejemplo busco firefox y luego su PID:

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

Entonces su código será:

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

Segunda forma : solo busca algo en el /proc/$PIDdirectorio. Estoy usando "exe" en este ejemplo, pero puedes usar cualquier otra cosa.

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

Entonces su código será:

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

Por cierto: ¿qué tiene de malo kill -9 $PID || true?


EDITAR:

Después de pensarlo durante unos meses ... (alrededor de 24 ...) la idea original que di aquí es un buen truco, pero altamente inportable. Si bien enseña algunos detalles de implementación de Linux, no funcionará en Mac, Solaris o * BSD. Incluso puede fallar en futuros núcleos de Linux. Por favor, use "ps" como se describe en otras respuestas.

elcuco
fuente
al menos la parte kill -9 parece incorrecta (no mata los subprocesos)
nurettin
¿Por qué obtengo [: missing `] 'cuando uso la primera forma?
tenmiles
1
/proc/$PID/exeNo es un archivo normal. Por lo tanto, [ -f /proc/$PID/exe ]siempre devolverá un falseresultado. Tratar [ -h /proc/$PID/exe ].
Alexander Yancharuk el
8

Parece que quieres

wait $PID

que volverá cuando $pidtermine.

De lo contrario, puede usar

ps -p $PID

para verificar si el proceso aún está vivo (esto es más efectivo que kill -0 $pidporque funcionará incluso si no posee el pid).

Gagan Gami
fuente
1
esperar no es tan efectivo ya que el proceso debería ser hijo del shell actual o dará:pid 123 is not a child of this shell
Calumah
7

Creo que es una mala solución, que se abre a las condiciones de carrera. ¿Qué pasa si el proceso muere entre su prueba y su llamado a matar? Entonces matar fallará. Entonces, ¿por qué no simplemente intentar matar en todos los casos y verificar su valor de retorno para averiguar cómo fue?

relajarse
fuente
Desafortunadamente, el código de salida de kill (1) no distingue las diferentes situaciones de error (parece que incrementa el valor de salida en uno por cada proceso que no pudo señalar). si al OP no le importa escribir su propio contenedor kill (2), podría hacer que salga con diferentes valores basados ​​en el valor de ERRNO después de una llamada fallida kill (2).
solo alguien
en este momento solo estoy haciendo kill -9 sin verificación, solo recibo un error "el proceso no existe" si no existe, lo cual no es muy ordenado. ¿Cómo probaría lo que pasó?
Richard H
14
No descuidadamente kill -9. Eso mata instantáneamente el proceso y no le da la oportunidad de limpiar después de sí mismo. En su lugar, use killel equivalente a kill -15. Si eso no funciona, debe averiguar por qué, y solo como último recurso kill -9.
Christoffer Hammarström
0

aquí almaceno el PID en un archivo llamado .pid (que es algo así como / run / ...) y solo ejecuto el script si aún no se está ejecutando.

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

nota: hay una condición de carrera ya que no comprueba cómo se llama ese pid. Si el sistema se reinicia y existe .pid pero es utilizado por una aplicación diferente, esto podría tener "consecuencias imprevistas".

inválida magia
fuente
0

Por ejemplo, en GNU / Linux puedes usar:

Pid=$(pidof `process_name`)

if [ $Pid > 0 ]; then

   do something
else

   do something
fi 

O algo como

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

y eso te muestra el nombre de la aplicación, solo el nombre sin ID.

inukaze
fuente
1
pidofno devuelve un número negativo, ya que un PID negativo no tiene ningún sentido, y no puede matar init, por lo que su condicional no tiene sentido (y además, necesitaría escapar >para evitar que realice una redirección). Desea verificar si hay un resultado vacío, pero, por supuesto, como cualquier herramienta decente, pidofestablece un código de salida para decirle si funcionó, por lo que la solución adecuada es if Pid=$(pidof 'process_name'); then ...o (si no necesita el valor Pidmás adelante) simplementeif pidof 'process_name'; then...
tripleee
@tripleee tiene razón, el pidofejemplo está lleno de malentendidos sobre cómo testfunciona bash . gnu.org/software/bash/manual/html_node/…
Bruno Bronosky
0

el código a continuación verifica si mi proceso se está ejecutando, si es así, no haga nada.

verifiquemos los mensajes nuevos de Amazon SQS solo cada hora y solo si el proceso no se está ejecutando.

#!/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 $?
Brian Sanchez
fuente