Por que obtenho status de saída diferente para ps | grep em um script?

11

Estou correndo abaixo do script:

#!/bin/bash

ps ax  | grep -q [v]arnish
if [ $? -eq 0 ];then
        echo varnish is running...
        exit 0
else
        echo "Critical : varnish is not running "
        exit 2
fi

A saída é como:

[root@server ~]# sh -x check_varnish_pro.sh
+ ps ax
+ grep -q '[v]arnish'
+ '[' 0 -eq 0 ']'
+ echo varnish is running...
varnish is running...
+ exit 0

Quando eu executo o mesmo na linha de comando, estou recebendo o status de saída como 1:

[root@server ~]# ps ax  | grep -q [v]arnish; echo $?
1

O caso é como o verniz não está instalado no servidor. Este script funciona bem em um servidor onde o verniz está instalado.

Por que status de saída diferente quando executado usando script e linha de comando? Como melhorar este script?

    
por prado 14.01.2017 / 08:42

3 respostas

9

Quando você executa um script chamado check_varnish_pro.sh the test

ps ax  | grep -q [v]arnish

é bem-sucedido porque há um script chamado check_ verniz _pro em execução.

    
por 14.01.2017 / 14:16
14

Em geral, é uma má ideia tentar a abordagem simples com ps e grep para tentar determinar se um determinado processo está sendo executado.

Você seria muito melhor usar pgrep para isso:

if pgrep "varnish" >/dev/null; then
  echo "Varnish in running"
else
  echo "Varnish is not running"
fi

Consulte o manual para pgrep . Em alguns sistemas (provavelmente não no Linux), você obtém um sinal -q que corresponde ao mesmo sinalizador para grep , o que elimina a necessidade de redirecionar para /dev/null . Há também um sinalizador -f que executa a correspondência na linha de comando completa em vez de apenas no nome do processo. Também é possível limitar a correspondência a processos pertencentes a um usuário específico usando -u .

A instalação de pgrep também oferece acesso a pkill , que permite sinalizar processos com base em seus nomes.

Além disso, se este é um daemon de serviço , e se o seu sistema Unix tiver uma maneira de consultá-lo para obter informações (por exemplo, se ele está ativo ou não), então esse é o > adequada forma de verificar.

No Linux, você tem systemctl ( systemctl is-active --quiet varnish retornará 0 se estiver em execução, 3 caso contrário), no OpenBSD você terá rcctl , etc.

Agora, para o seu script:

No seu script, você analisa a saída de ps ax . Essa saída conterá o nome do próprio script, check_varnish_pro.sh , que obviamente contém a string varnish . Isso lhe dá um falso positivo. Você teria percebido isso se tivesse executado sem o sinal -q para grep durante o teste.

#!/bin/bash
ps ax | grep '[v]arnish'

Executando:

$ ./check_varnish_pro.sh
31004 p1  SN+     0:00.04 /bin/bash ./check_varnish_pro.sh

Outra questão é que, embora você tente "ocultar" o processo grep de ser detectado pelo próprio grep usando [v] no padrão. Essa abordagem falhará se você executar o script ou a linha de comando em um diretório que tenha um arquivo ou diretório denominado varnish (nesse caso, você obterá um falso positivo novamente). Isso ocorre porque o padrão é sem aspas e o shell executará a globalização do nome de arquivo com ele.

Veja:

bash-4.4$ set -x
bash-4.4$ ps ax | grep [v]arnish
+ ps ax
+ grep '[v]arnish'
bash-4.4$ touch varnish
+ touch varnish
bash-4.4$ ps ax | grep [v]arnish
+ ps ax
+ grep varnish
91829 p2  SN+p    0:00.02 grep varnish

A presença do arquivo varnish fará com que o shell substitua [v]arnish pelo nome do arquivo varnish e você obtenha um hit no padrão na tabela de processos (o processo grep ).

    
por 14.01.2017 / 09:03
3

@AlexP explica muito sucintamente o que realmente está acontecendo, mas a ideia da @ Kusalananda de usar pgrep / pkill para um processo crítico é strongmente desencorajado . Melhor soluções incluem:

  • Perguntando ao serviço se está sendo executado. systemctl status varnishd deve cuidar disso em uma instalação moderna * nix.
  • Se por alguma circunstância infeliz você não tiver um serviço disponível, basta alterar o script de inicialização para relatar o problema assim que o processo terminar:

    varnish || true
    some_command_to_send_an_alert_that_the_service_has_died
    
  • Alternativamente, altere o script que inicia o serviço para registrar o PID e, em seguida, verifique o estado periodicamente com kill -0 "$pid" .
por 14.01.2017 / 15:00