Forma de bash para verificar se um processo já está sendo executado em segundo plano (e pular a reexecução com base nisso)?

10

Posso criar uma linha de comando bash que execute apenas um determinado comando se o processo ainda não estiver em execução (em segundo plano)?

Como faço para verificar *, se um comando já está em execução?

(para que eu possa adicionar o próximo comando com && entre eles, então o próximo só será executado se o primeiro for verdadeiro).

*: teste, determine, descubra, descubra

    
por n611x007 10.06.2013 / 09:42

10 respostas

6

Use daemontools . Você pode usar svok para verificar se um processo de serviço / daemon / plano de fundo está sendo executado no momento.

Para outros métodos, consulte:

por 10.06.2013 / 11:29
2

Eu usei essa técnica de tempos em tempos:

$ pgrep <process name> || <process name>

Antes de pgrep , costumava ser feito assim:

$ ps -eaf | grep -q <[p]rocess name> || <process name>

exemplo

O bit com o [p] faz com que o grep não seja encontrado como resultado.

$ ps -eaf | grep -q [s]leep || sleep 10
    
por 10.06.2013 / 13:38
2

Isso pode ser complicado, porque você pode ter instâncias separadas do mesmo processo que vivem de forma independente. Por exemplo, servidores ouvindo em diferentes portas ou serviços em execução como usuários diferentes. Para distinguir entre essas instâncias, você precisa atribuir a cada uma delas uma tag exclusiva. A tag é geralmente um arquivo, mas pode ser um soquete local no namespace abstrato, uma porta TCP etc. - qualquer identificador exclusivo serve. Quando a tag é um arquivo, ela pode ser um arquivo regular contendo um ID de processo (um pidfile) ou um pipe ou soquete nomeado no qual o arquivo está escutando etc. Idealmente, a tag é um ponto de extremidade de comunicação que permite aos clientes se conectarem para esse processo.

Cada um desses diferentes tipos de tags resulta em uma maneira diferente de verificar se a instância que você está procurando está funcionando. Por exemplo, com um soquete de arquivo local, tente conectar-se a ele e inicie o processo se não houver processo escutando nesse soquete. Se a tag for um pidfile, verifique se há um processo com essa ID de processo, mas cuidado, pois isso é frágil, pois, se o processo tiver morrido, pode haver um processo não relacionado que reutilizou sua ID. Tenha em atenção que, se dois clientes tentarem alcançar o processo num curto espaço de tempo, ambos poderão descobrir que o processo não existe e ambos tentarem iniciá-lo; proteger adequadamente desta condição de corrida pode ser complicado.

É mais fácil gerenciar instâncias quando todas são iniciadas pelo mesmo processo de supervisor, e esse processo de supervisor detecta quando as instâncias morrem e reage de acordo. Se o programa não responder em um ponto de extremidade de comunicação conhecido e não for gerenciado por um programa de supervisor, a tag do homem pobre é um pidfile: um arquivo que contém o ID do processo. Quando você inicia o processo, escreva o pid em um arquivo com um nome pré-arranjado. Quando você precisar que o processo exista, leia o pidfile e veja se há um processo com esse pid. Quando você mata o processo, apague o pidfile. O problema mais saliente com um pidfile não supervisionado é que se o processo morrer, seu pid pode ser reutilizado por algum processo não relacionado. Você deve pelo menos verificar o nome do processo ou o executável do processo para garantir que está falando com o processo correto. Muitas variantes unix têm um comando pgrep : pgrep SOMENAME lista os processos cujo nome contém SOMENAME como substring, com opções adicionais para limite a um usuário em particular, para exigir uma correspondência exata, para alterar qual das várias noções possíveis de "nome do processo" é usada, etc.

    
por 10.06.2013 / 19:27
1

Você pode usar essa abordagem:

if [[ -z $(ps -C appname -opid=) ]]; then
    appname && secondapp
fi
    
por 10.06.2013 / 10:03
1

Outras opções:

  • %código%
    • Corresponde apenas aos primeiros 15 caracteres no GNU / Linux
    • Não inclui ancestrais no OS X
  • %código%
    • Corresponde apenas aos primeiros 15 caracteres no GNU / Linux
    • pgrep -xq processname remove as partes do dirname no OS X

No GNU / Linux ps -eo comm= | sed 's|.*/||' | grep -xq processname trunca nomes de comandos para 15 caracteres e sed 's|.*/||' e ps -o comm correspondem apenas aos primeiros 15 caracteres.

pgrep (nomes de comando de correspondência) não é suportado no OS X.

No OS X ps -C imprime os caminhos absolutos dos comandos e ps -C apenas imprime os nomes dos comandos. Em% GNUps -o comm apenas imprime nomes de comandos e ps -co comm tem um significado diferente.

O pgrep do OS X não inclui processos ancestrais (como bash, Terminal ou launchd) sem ps -o comm . O pgrep do GNU inclui-os por padrão e não suporta -c .

-a e -a não implicam grep -x , portanto use pgrep -x se o nome do processo puder conter caracteres regex.

    
por 10.06.2013 / 12:26
1

Sinto muito, mas todas essas soluções não suportam contab, pois a mesma linha de comando aparecerá duas vezes no resultado 'ps'.

Então aqui está a minha:

## Test pour voir si le même script tourne déjà
## Un fichier .pid est utilisé pour stocké le numéro de process
## Si le pid est en train de tourner alors on sort.
lock_file=$0".pid"
[ -r $lock_file ] && read pid <$lock_file
if [ "$pid" -gt 1 ] && [ 'ps --no-headers -p "$pid" | wc -l' -gt 0 ] ; then
    echo "WARNING : le process $pid tourne deja : $0"
    ps -edf | grep 'basename $0' | grep -v grep
    echo "WARNING : Arrêt de cette instance ($$)."
    exit 7
fi
echo $$ >$lock_file
    
por 19.02.2015 / 14:53
0

Com Bash

#!/usr/bin/env bash

[[ $# -eq 0 ]] && { echo -e "Usage:\t\t $0 <Process_name>  <Command here>"; exit 1;  }

ifnotrun(){
        local p=$1
        if ! ps -C "$1" -opid=
        then
                cmd=($@)
                echo ${cmd[@]:1}
        else
                echo "Process \"$p\" Already Running.."
                exit 1
        fi

}

ifnotrun $*

Nota: - remova echo se a saída parecer Ok.

    
por 10.06.2013 / 10:24
0

Vou explicar o caso em que você executa o comando no beckgreoud. O "$!" salve o PID do último processo em segundo plano. Assim, você pode usá-lo para encontrá-lo nas tabelas do processo seguindo as respostas acima:

sleep 4 &
ps -ef | grep -w  $!  ...

O comando interno "jobs" - tente isto:

sleep 4&
J='jobs'
while [ "$J" ]; do
        sleep 1
        jobs # This line flush the jobs' bufer.
        J='jobs'
done

Com relação ao "& &" opção

Em vez de & & use o comando wait. No exemplo a seguir myproc2 não será executado até que myproc1 termine:

myproc1 &
wait
myproc2
    
por 10.06.2013 / 19:29
0

Veja o estado do seu processo:

ps -lp $(pgrep <YOUR_PROCESS_NAME>) | tail -1 | awk '{print $11}'

Referência:

D    uninterruptible sleep (usually IO)
R    running or runnable (on run queue)
S    interruptible sleep (waiting for an event to complete)
T    stopped, either by a job control signal or because it is being traced
W    paging (not valid since the 2.6.xx kernel)
X    dead (should never be seen)
Z    defunct ("zombie") process, terminated but not reaped by its parent

Por exemplo, usei-o para reproduzir ou pausar condicionalmente o meu processo sox em uma sessão do tmux:

/usr/local/bin/tmux if-shell -t sox "[ $(ps -lp $(pgrep sox) | tail -1 | awk '{print $11}') == 'T' ]" \
  'send -t sox "fg" Enter' \
  'send -t sox C-z'
    
por 05.01.2016 / 17:55
-1

Você pode usá-lo dentro de um script:

if [ 'ps -ef | grep "script.sh" | grep -v grep | wc -l' -gt 1 ] ; then
echo "RUNNING...."
else
echo "NOT RUNNING..."
fi
    
por 19.08.2014 / 23:17