Como verificar se existe um ID do processo (PID)

184

Em um script bash, desejo fazer o seguinte (em pseudo-código):

if [ a process exists with $PID ]; then

    kill $PID 

fi

Qual é a expressão apropriada para a declaração condicional?

Richard H
fonte

Respostas:

182

Para verificar a existência de um processo, use

kill -0 $pid

Mas, como o @unwind disse, se você vai matá-lo de qualquer maneira, apenas

kill $pid

ou você terá uma condição de corrida.

Se você deseja ignorar a saída de texto kille fazer algo com base no código de saída, pode

if ! kill $pid > /dev/null 2>&1; then
    echo "Could not send SIGTERM to process $pid" >&2
fi
Christoffer Hammarström
fonte
1
olhando para a página de manual, kill -0 é: "código de saída indica se um sinal pode ser enviado". Então isso realmente mata um processo ou apenas diz se ele pode ser morto?
Richard H
24
killé um pouco errado, pois não necessariamente mata o processo. Apenas envia um sinal ao processo. kill $PIDé equivalente a kill -15 $PID, que envia o sinal 15, SIGTERM para o processo, que é uma instrução para finalizar. Não há sinal 0, é um valor especial que informa killapenas para verificar se um sinal pode ser enviado ao processo, o que é, na maioria dos casos, mais ou menos equivalente a verificar se ele existe. Veja linux.die.net/man/2/kill e linux.die.net/man/7/signal
Christoffer Hammarström
43
Isso tem o problema de que, se o processo não pertencer ao usuário em execução, talvez você não tenha permissões para chamar kill -0. Melhor usar ps -p $ PID> / dev / null 2> & 1, que permite ver o status do processo, mesmo se você não tiver permissões para enviar um sinal.
Mckoss #
6
@ckoss: Nesse caso, ele não pode matá-lo de qualquer maneira.
Christoffer Hammarström
2
Então, eu acho - para usar kill -0, eu tenho que fazer o seguinte: kill -0 25667 ; echo $?- e, se eu receber um 0retorno, o processo com esse PID pode ser morto; e se o processo PID (digamos) não existir, o $?será 1, indicando uma falha. Isso está correto?
Sdaau
264

A melhor maneira é:

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

O problema com:

kill -0 $PID

é que o código de saída será diferente de zero, mesmo se o pid estiver em execução e você não tiver permissão para eliminá-lo. Por exemplo:

kill -0 1

e

kill -0 $non-running-pid

tenha um código de saída indistinguível (diferente de zero) para um usuário normal, mas o processo init (PID 1) certamente está em execução.

DISCUSSÃO

As respostas que discutem as condições de matança e raça são exatamente corretas se o corpo do teste for uma "matança". Eu vim procurando pelo general " como você testa a existência de PID no bash ".

O método / proc é interessante, mas, em certo sentido, quebra o espírito da abstração do comando "ps", ou seja, você não precisa procurar no / proc porque, e se Linus decidir chamar o arquivo "exe" de outra coisa?

FDS
fonte
1
ps -p sempre retorna o estado de 0 para mim
IttayD
1
ps -p #### funcionou bem para mim no Ubuntu 14.04, +1 obrigado!
Ligemer
3
ps -p sempre retorna código de status 0 no OS X porque ele imprime uma lista vazia de processo quando ele não corresponde a qualquer processo em execução
Douglas Correa
Posso confirmar que no macOS Sierra isso funciona. Além disso, o -pé desnecessário, pelo menos nesse caso. ps $PIDtem exatamente o mesmo resultado.
user137369
A portabilidade é um bom motivo para evitar o uso de / proc, mas o Linux que quebra sua ABI não é um cenário com o qual me preocuparia particularmente.
David Roundy
67
if [ -n "$PID" -a -e /proc/$PID ]; then
    echo "process exists"
fi

ou

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

No último formulário, -o pid=é um formato de saída para exibir apenas a coluna de ID do processo sem cabeçalho. As aspas são necessárias para que o operador de sequência não vazia -nforneça um resultado válido.

user2683246
fonte
1
O segundo método também funciona no Mac, como um acréscimo adicional (o Mac OS X não possui / proc FS). Você pode, no entanto, evitar o uso de um subshell e usá-lo no Mac e no Linux:if ps -p"$PID" -o "pid=" >/dev/null 2>&1; then echo "Process is running..."; fi
será
Infelizmente, as psopções e os recursos tendem a variar entre as plataformas, por isso ainda não é totalmente portátil.
Tripleee
1
se $PIDestiver vazio, [ -e /proc/$PID ]ainda retornará verdadeiro, pois o /proc/diretório ainda existe.
26518 Magne
34

pscomando com -p $PIDpode fazer isso:

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

Você tem duas maneiras:

Vamos começar procurando uma aplicação específica no meu laptop:

[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 os exemplos agora procurarão pelo PID 3358.

Primeira maneira : Execute "ps aux" e grep para o PID na segunda coluna. Neste exemplo, procuro o Firefox e, em seguida, o PID:

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

Portanto, seu código será:

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

Segunda maneira : basta procurar algo no /proc/$PIDdiretório. Estou usando "exe" neste exemplo, mas você pode usar qualquer outra coisa.

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

Portanto, seu código será:

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

BTW: o que há de errado com kill -9 $PID || true?


EDITAR:

Depois de pensar nisso por alguns meses .. (cerca de 24 ...), a ideia original que dei aqui é um truque agradável, mas altamente não transportável. Embora ensine alguns detalhes de implementação do Linux, ele não funcionará no Mac, Solaris ou * BSD. Pode até falhar em futuros kernels do Linux. Por favor - use "ps" como descrito em outras respostas.

elcuco
fonte
pelo menos o kill -9 parte parece errado (não mata subprocessos)
nurettin
Por que recebo [: missing `] 'quando uso a primeira maneira?
Tenmiles
1
/proc/$PID/exenão é um arquivo regular. Então, [ -f /proc/$PID/exe ]sempre retornará um falseresultado. Tente [ -h /proc/$PID/exe ].
Alexander Yancharuk
8

Parece que você quer

wait $PID

que retornará quando $pidterminar.

Caso contrário, você pode usar

ps -p $PID

para verificar se o processo ainda está ativo (isso é mais eficaz do que kill -0 $pidporque funcionará mesmo se você não possuir o pid).

Gagan Gami
fonte
1
espera não é tão eficaz como o processo deve ser filho do shell atual ou ele vai dar:pid 123 is not a child of this shell
Calumah
7

Eu acho que é uma péssima solução, que se abre para condições de corrida. E se o processo morrer entre o seu teste e a sua chamada para matar? Então matar falhará. Então, por que não apenas tentar matar em todos os casos e verificar seu valor de retorno para descobrir como foi?

descontrair
fonte
Infelizmente, o código de saída do kill (1) +1 não distingue as diferentes situações de erro (parece que incrementa o valor da saída em um para cada processo que não conseguiu sinalizar). se o OP não se importar em escrever seu próprio wrapper kill (2), ele poderá sair com valores diferentes com base no valor de ERRNO após uma falha na chamada (2).
apenas alguém
No momento, estou apenas matando -9 sem verificação - recebo o erro "processo não existe" se não existir, o que não é muito arrumado. Como eu testaria o que aconteceu?
Richard H
14
Não descuide kill -9. Isso acaba instantaneamente com o processo, sem chance de se limpar. Em vez disso, use o killequivalente a kill -15. Se isso não funcionar, você deve descobrir o porquê e apenas como último recurso kill -9.
Christoffer Hammarström
0

aqui eu guardo o PID em um arquivo chamado .pid (que é como like / run / ...) e só executo o script se ele ainda não estiver sendo executado.

#!/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: existe uma condição de corrida, pois não verifica como esse pid é chamado. se o sistema for reiniciado e o .pid existir, mas for usado por um aplicativo diferente, isso poderá gerar 'consequências imprevistas'.

invalidmagic
fonte
0

Por exemplo, no GNU / Linux, você pode usar:

Pid=$(pidof `process_name`)

if [ $Pid > 0 ]; then

   do something
else

   do something
fi 

Ou algo como

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

e isso mostra o nome do aplicativo, apenas o nome sem ID.

inukaze
fonte
1
pidofnão retorna um número negativo, pois um PID negativo não faz sentido e você não pode matar init, portanto, seu condicional não faz sentido (além disso, você precisaria escapar do >para impedir que ele redirecionasse). Você deseja verificar se há um resultado vazio, mas é claro que, como qualquer ferramenta decente, pidofdefine um código de saída para informar se funcionou; portanto, a solução adequada é if Pid=$(pidof 'process_name'); then ...ou (se você não precisar do valor Pidposteriormente) simplesmenteif pidof 'process_name'; then...
triplee
@tripleee está certo, o pidofexemplo está cheio de mal-entendidos sobre como o bash testfunciona. gnu.org/software/bash/manual/html_node/…
Bruno Bronosky;
0

O código abaixo verifica se meu processo está em execução; caso contrário, não faça nada.

vamos verificar novas mensagens do Amazon SQS a cada hora apenas e somente se o processo não estiver em execução.

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