¿Por qué obtengo un estado de salida diferente para ps | grep en un script?

11

Estoy ejecutando debajo del 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

El resultado es 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

Cuando ejecuto lo mismo en la línea de comando, obtengo el estado de salida como 1:

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

El caso es que el barniz no está instalado en el servidor. Este script funciona bien en un servidor donde está instalado el barniz.

¿Por qué un estado de salida diferente cuando se ejecuta usando script y línea de comando? ¿Cómo mejorar este script?

prado
fuente
Utilice un sistema de supervisión de procesos real, no este tipo de piratería informática. Es casi seguro que su sistema operativo tendrá una forma integrada de garantizar que sus demonios que desea mantener se reinicien automáticamente en caso de falla, ya sea upstart, daemontools, systemd, launchd o una de las muchas, muchas otras alternativas. Todos serán más robustos y capaces que este tipo de piratería manual.
Charles Duffy

Respuestas:

10

Cuando ejecutas un script llamado check_varnish_pro.shtest

ps ax  | grep -q [v]arnish

es exitoso porque hay una secuencia de comandos llamada check_barniz en_pro ejecución.

AlexP
fuente
14

En general, es una mala idea probar el enfoque simple pse grepintentar determinar si se está ejecutando un proceso determinado.

Sería mucho mejor usarlo pgreppara esto:

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

Vea el manual para pgrep. En algunos sistemas (probablemente no en Linux), se obtiene un -qindicador que corresponde al mismo indicador para el grepcual se elimina la necesidad de redirigir /dev/null. También hay una -fbandera que realiza la coincidencia en la línea de comando completa en lugar de solo en el nombre del proceso. También se puede limitar la coincidencia a los procesos que pertenecen a un usuario específico -u.

La instalación pgreptambién le da acceso a lo pkillque le permite señalar procesos basados ​​en sus nombres.

Además, si este es un demonio de servicio , y si su sistema Unix tiene una forma de consultar información (por ejemplo, si está en funcionamiento o no), entonces esa es la forma correcta de verificarlo.

En Linux, tiene systemctl( systemctl is-active --quiet varnishdevolverá 0 si se está ejecutando, 3 de lo contrario), en OpenBSD que tiene rcctl, etc.


Ahora a tu guión:

En su secuencia de comandos, analiza la salida de ps ax. Esta salida contendrá el nombre del script en sí check_varnish_pro.sh, que obviamente contiene la cadena varnish. Esto te da un falso positivo. Habría descubierto esto si lo hubiera ejecutado sin la -qbandera durante la grepprueba.

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

Ejecutándolo:

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

Otro problema es que aunque intenta "ocultar" el grepproceso para que no sea detectado por grepsí mismo mediante el uso [v]del patrón. Ese enfoque fallará si ejecuta el script o la línea de comando en un directorio que tiene un archivo o directorio nombrado varnishen él (en cuyo caso obtendrá un falso positivo, de nuevo). Esto se debe a que el patrón no está entre comillas y el shell realizará el bloqueo de nombre de archivo con él.

Ver:

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

La presencia del archivo varnishhará que el shell se reemplace [v]arnishcon el nombre del archivo varnishy obtendrá un golpe en el patrón en la tabla de procesos (el grepproceso).

Kusalananda
fuente
44
porque todo es un archivo "en linux land".
zee
@ z_- No estoy muy seguro de cómo está conectado, pero esto es cierto incluso en unidades que no son Linux.
Kusalananda
44
No solo el proceso grep; el script que se nombra check_varnish_pro.shtambién es un factor.
TNW
@TNW No lo vi al principio, pero tienes razón. Agregaré eso.
Kusalananda
3

@AlexP explica muy sucintamente lo que realmente está sucediendo, pero la idea de @ Kusalananda de usar pgrep/ pkillpara un proceso crítico se desaconseja . Las mejores soluciones incluyen:

  • Preguntar al servicio si se está ejecutando. systemctl status varnishddebería ocuparse de eso en una instalación moderna * nix.
  • Si por alguna circunstancia desafortunada no tiene un servicio disponible, simplemente puede cambiar el script de inicio para informar el problema tan pronto como finalice el proceso:

    varnish || true
    some_command_to_send_an_alert_that_the_service_has_died
    
  • Alternativamente, cambie el script que inicia el servicio para registrar el PID y luego verifique el estado periódicamente con kill -0 "$pid".
l0b0
fuente
Estoy de acuerdo, solo estaba abordando los aspectos del problema del script de shell. Tenga en cuenta que systemctlcasi solo está disponible en Linux (AFAIK), y no en todos los sistemas modernos tipo Unix.
Kusalananda
La pregunta original tenía la etiqueta "linux"; No estoy seguro de por qué eso fue eliminado por @muru.
l0b0
Gracias l0b0. Tenía dos preguntas: "Por qué" y "Cómo mejorar". La respuesta de @ AlexP resolvió mi primera pregunta y su respuesta es una mejor solución para la segunda pregunta. Pero Kusalananda explica cosas relacionadas con esto que creo que serán útiles para las personas que tienen problemas similares. Así que ahora estoy confundido sobre cuál aceptar como respuesta.
prado