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?

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

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?


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.


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

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.


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).


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?


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'.


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.


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 $?
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.