Como determinar se um processo está em execução ou não e usá-lo para criar um script de shell condicional?


108

Como posso determinar se um processo está em execução ou não e depois fazer com que um script bash execute algumas coisas com base nessa condição?

Por exemplo:

  • se o processo abcestiver em execução, faça isso

  • se não estiver em execução, faça isso.


1
Sinta-se importante observar que nenhuma das soluções abaixo leva em consideração o estado do processo. Um comentário em uma das minhas perguntas me trouxe aqui, mas uma resposta me levou a diferentes estados de um programa, como zombieprocesso '(não é o que eu descreveria como um processo "em execução"). Uma lista completa do que os STATvalores da coluna, na saída de ps, indica está aqui para aqueles que desejam escrever uma resposta que acomode isso ou editar seus próprios.
user66001


melhor maneira de verificar se há processo existe: stackoverflow.com/questions/3043978/...
Trevor Boyd Smith

Respostas:


166

Um script bash para fazer algo assim seria algo como isto:

#!/bin/bash

# Check if gedit is running
# -x flag only match processes whose name (or command line if -f is
# specified) exactly match the pattern. 

if pgrep -x "gedit" > /dev/null
then
    echo "Running"
else
    echo "Stopped"
fi

Este script está apenas verificando se o programa "gedit" está em execução.

Ou você só pode verificar se o programa não está sendo executado assim:

if ! pgrep -x "gedit" > /dev/null
then
    echo "Stopped"
fi

@DreadPirateShawn, você pode me dizer por que usar / dev / null e não simplesmente um 0? Usar o número torna o código mais legível, pelo menos para um noob (como eu). Sem redirecionamento, sem nada
Silviu

2
@Silviu huh? Como pesquisar no Google /dev/null: "/ dev / null redireciona a saída padrão do comando para o dispositivo nulo, que é um dispositivo especial que descarta as informações gravadas nele" ... o uso 0redireciona a saída do comando para um arquivo chamado 0. Nesse caso, aconselho que você se sinta mais confortável > /dev/null- você o verá em qualquer lugar, pois é a maneira padrão / adequada de descartar a saída.
DreadPirateShawn

Woot obrigado, usei isso para um pequeno script agradável que verifica se um programa está sendo executado antes de ser executado. (embora eu tive que estendê-lo um pouco desde executável do Google Chrome não tem o mesmo nome que ele está comando executado, o nome exec é apenas cromo.)
Cestarian

3
Adicione o -xparâmetro para pgrepque ele procure a aplicação exata, caso contrário, a correção será falsa se encontrar a mesma string dentro do nome de outro aplicativo. Passei apenas 1 hora para descobrir isso.
Thanos Apostolou

1
Para verificar se o programa não está sendo executado, use! pgrep
Mohammed Noureldin

36

Qualquer solução que use algo parecido ps aux | grep abcou com pgrep abcdefeito.

Por quê?

Como você não está verificando se um processo específico está em execução, está verificando se há algum processo em execução que coincida abc. Qualquer usuário pode criar e executar facilmente um executável chamado abc(ou que contenha abcalgum lugar em seu nome ou argumentos), causando um falso positivo para o seu teste. Existem várias opções que você pode aplicar para ps, grepe pgreppara restringir a busca, mas você ainda não terá um teste confiável.

Então, como faço para testar com segurança um determinado processo em execução?

Isso depende do que você precisa para o teste.

Quero garantir que o serviço abc esteja em execução e, se não estiver, inicie-o

É para isso que servem o init e o upstart. Eles iniciarão o serviço e garantirão que seu pid seja armazenado em um arquivo de pid. Tente iniciar o serviço novamente (via init ou upstart) e ele verificará o pidfile e inicie-o se ele não estiver lá ou aborte se já estiver em execução. Isso ainda não é 100% confiável, mas é o mais próximo possível.

Consulte Como posso verificar se meu servidor de jogos ainda está em execução ... para outras soluções.

abc é o meu script. Preciso garantir que apenas uma instância do meu script esteja em execução.

Nesse caso, use um arquivo de bloqueio ou um lockdir. Por exemplo

#!/usr/bin/env bash

if ! mkdir /tmp/abc.lock; then
    printf "Failed to acquire lock.\n" >&2
    exit 1
fi
trap 'rm -rf /tmp/abc.lock' EXIT  # remove the lockdir on exit

# rest of script ...

Consulte a Bash FAQ 45 para outras formas de bloqueio.


3
Embora isso seja tecnicamente verdade, nunca encontrei pessoalmente esse problema na vida real. A maioria dos programas não muda seus nomes de maneira a interromper os scripts. Assim, para scripts simples, algo como pgrepou psé perfeitamente adequado e sua abordagem parece um exagero. Se você estiver escrevendo um script para distribuição pública, deve escrevê-lo da maneira mais segura possível.
Scott Severance

2
Programas @ScottSeverance que mudam de nome não é o problema; isso exigiria intervenção independentemente. Outros usuários executando o mesmo programa, ou outros programas com nomes semelhantes, que repentinamente farão com que o script obtenha falsos positivos e, assim, faça a coisa errada. Eu apenas prefiro "funciona" em vez de "principalmente funciona".
geirha

2
Eu errei. Mas muitos de nós executamos sistemas de usuário único. E em uma situação de vários usuários, é fácil também grep para o nome de usuário.
Scott Severance

1
e se o seu script falhar durante o tempo de execução e morrer antes de desbloquear o arquivo?
Jsp093121

2
@ jp093121 A interceptação EXIT é acionada quando o script sai. Se ele sai porque atinge o final do script, um comando de saída ou recebe um sinal (que pode ser tratado), o rmcomando é executado. Portanto, desde que termine após a armadilha ter sido configurada, a trava deverá desaparecer.
geirha

18

Isto é o que eu uso:

#!/bin/bash

#check if abc is running
if pgrep abc >/dev/null 2>&1
  then
     # abc is running
  else
     # abc is not running
fi

Em inglês simples: se 'pgrep' retornar 0, o processo está sendo executado, caso contrário, não é.


Leitura relacionada:

Bash Scripting :: Comparações de strings

Manuais do Ubuntu pgrep


thanx! Eu tentei isso também n ele funciona perfeitamente também :)
Nirmik

pgreptem o mesmo "recurso" de 15 caracteres limite mencionado anteriormente, assim, por exemplo, pgrep gnome-power-managertambém falham
Thorsen

1
Certifique-se de usar a -xopção do pgrep : " Corresponde apenas aos processos cujo nome (ou linha de comando se -f for especificado) corresponde exatamente ao padrão."
Alastair Irvine

5

Normalmente, tenho um pidof -x $(basename $0)em meus scripts para verificar se ele já está em execução.


2

Pensando na ideia de @ rommel-cid, você pode usar pidofcom o || (||) para executar um comando se o processo não existir e && para executar algo se o processo existir, criando assim uma condicional rápida se / então / outra. Por exemplo, aqui está um com um processo em execução (meu navegador chrome, cujo nome do processo é "chrome") e um teste para um processo que não existe. Eu suprimi a saída padrão usando 1> / dev / null para que não seja impressa:

$ (pidof chrome 1>/dev/null && echo "its running? ok, so am i then" ) || echo "it's not running? ok i'll run instea\
d"
its running? ok, so am i then
$ (pidof nosuchprocess 1>/dev/null && echo "its running? ok, so am i then" ) || echo "it's not running? ok i'll run\
 instead"
it's not running? ok i'll run instead
$

1

Nenhuma das soluções "simples" funcionou para mim porque o binário que preciso verificar não está instalado em todo o sistema; portanto, tenho que verificar com o caminho, o que, por sua vez, requer o uso da ps -ef | grepabordagem:

app="$_sdir/Logic 1.2.18 (64-bit)/Logic"

app_pid=`ps -ef | grep "$app" | awk '{print $2}'`

if `ps -p $app_pid > /dev/null`; then
    echo "An instance of logic analyzer is appear to be running."
    echo "Not starting another instance."
    exit 5
else
    nohup "$app" &> /dev/null &
fi

0

A primeira coisa que veio à minha mente para o seu problema:
ps aux | grep -i abcmostrará os detalhes do processo, se estiver em execução. Você pode corresponder ao número de linhas ou tempo durante o qual está sendo executado e comparar com zero ou qualquer outra manipulação. Quando você executa o comando acima, ele mostra pelo menos uma linha de saída, ou seja, detalhes sobre o processo criado pelo comando grep. Portanto, cuide disso.
Isso deve fazer como um simples hack. Coloque-o no script bash e veja se é útil.


0

Usando start-stop-daemon:

/sbin/start-stop-daemon --background --make-pidfile --pidfile /tmp/foo.pid -S --startas /usr/bin/program -- arg1 arg2

Funciona como usuário normal.


0

Eu descobri que a resposta aceita postada por @John Vrbanac não funcionou para mim e que a resposta postada por @geirha não responde à pergunta original.

A solução de John Vrbanac não funcionou para verificar se um processo PHP estava sendo executado ou não, estou executando o CentOS 7.

A resposta da @ geirha apenas garante que uma instância ainda não esteja em execução antes de iniciar outra. Esta não era a pergunta original, a questão original era verificar se um processo está sendo executado ou não.

Aqui está o que funcionou para mim:

Digamos que meu processo tenha a string "Jane" no nome do processo. Isso descobrirá se está sendo executado ou não. Isso funciona para scripts BASH e PHP.

ps -aux | grep "[J]ane" > /dev/null 2>&1
if [[ "$?" == "0" ]]; then
    echo "It's running"
else
    echo "It's not running"
fi

1
Ah, bem, como este é um site de perguntas e respostas sobre o Ubuntu, não é de surpreender que algumas das respostas aqui não funcionem no CentOS 7, pois o Linux está fora de tópico aqui. Outras versões do Linux são suportadas em unix.stackexchange.com
Elder Geek

embora o autor da resposta use o CentOS, essa resposta ainda é válida para o ubuntu.
Phillip -Zyan K Lee Stockmann

0
## bash

## function to check if a process is alive and running:

_isRunning() {
    ps -o comm= -C "$1" 2>/dev/null | grep -x "$1" >/dev/null 2>&1
}

## example 1: checking if "gedit" is running

if _isRunning gedit; then
    echo "gedit is running"
else
    echo "gedit is not running"
fi

## example 2: start lxpanel if it is not there

if ! _isRunning lxpanel; then
    lxpanel &
fi

## or

_isRunning lxpanel || (lxpanel &)

Nota : pgrep -x lxpanelou pidof lxpanelainda relata que lxpanelestá sendo executado mesmo quando está extinto (zumbi); Para obter um processo ativo e em execução, precisamos usar psegrep


-1

Em 23 de setembro de 2016, o pgrep parece exigir a opção "-x" para que o script de muru funcione.

#!/bin/bash

if pgrep -x "conky" > /dev/null 2>&1
then
  echo "conky running already"
else
  echo "now starting conky"
  conky
fi
exit 0

Eu tentei e testei o script acima em uma máquina Ubuntu 16.04.1. Desfrutar!


-1
#!/bin/bash
while [ true ]; do     # Endless loop.
  pid=`pgrep -x ${1}`  # Get a pid.
  if [ -z $pid ]; then # If there is none,
    ${1} &             # Start Param to background.
  else
    sleep 60           # Else wait.
  fi
done

1
Bem-vindo ao Ask Ubuntu! Eu recomendo editar esta resposta para expandi-la com detalhes específicos sobre o que isso faz. (Veja também Como faço para escrever uma boa resposta? Para o conselho geral sobre que tipos de respostas são consideradas mais valiosas sobre AskUbuntu.)
David Foerster

-3

isProcessRunning () {if [$ (pidof $ 1)> / dev / null]; então retval = 'true'; else retval = 'false'; fi; eco $ retval; }

isProcessRunning geany

verdadeiro

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.