Tubería condicional en bash (script personalizado)

Tubería condicional en bash (script personalizado)

¿Cómo puedo canalizar comandos y, dentro del script, decidir si se debe romper la tubería o no?

Es similar aesta pregunta. Pero en lugar de eso, awkme gustaría usar mi propio script:

check_ip | update_bind9

check_ipDebe encontrar la IP externa ( curl -s ifconfig.co) y compararla con la IP almacenada en un archivo ( ~/.ip).

Aquí está la pregunta principal:

Si la IP ha cambiado, check_ipdebe pasar la IP a través de la tubería. Si no, debería romper la tubería.

¿ check_ipEso rompe la tubería o update_bind9ignora la llamada si no se llama con la IP?

Hice algunas pruebas, llamando: check_ip | echo "ok".

Lo intenté exit 0, exit 1, return true, return false. Lo intenté set -e. Sin éxito.

Respuesta1

Todos los componentes de una tubería.comenzar simultáneamente– el segundo comando siempre se iniciará sin importar lo que suceda en el primer comando.

Entonces es el segundo comando el que necesita manejar la entrada estándar vacía.


Pero yo diría que las pipas no son una buena opción para esto en primer lugar.

(¿Quizás estás confundiendo |(tubería) con ||(booleano OR)? Este últimoesfrecuentemente se usa como una alternativa más corta a si/entonces, por ejemplo, x || ysolo llamará a y cuando x falle – y de manera similar, x && ysolo llamará a y cuando x tenga éxito.)

En general, deberías utilizar un bloque si/entonces. Por ejemplo, si check_ipdevuelve 0 (éxito) cuando las direcciones son diferentes pero 1 (fracaso) cuando son iguales, se vería así:

if addr=$(check_ip); then
    echo "$addr" | update_bind9
fi

Alternativamente, si update_bind9 puede determinar la dirección por sí solo (sin leer la entrada estándar), sería así:

if check_ip_needs_updating; then
    update_bind9
fi

Respuesta2

esta otra respuestaes bueno. Sin embargo, si realmente necesita canalizar de forma condicional, es posible que encuentreifneútil:

ifneejecuta el siguiente comando si y solo si la entrada estándar no está vacía.

En tu caso será como check_ip | ifne update_bind9.

Lo más probable ifnees que no esté instalado en su Linux de forma predeterminada. En mi Debian 10 está en el moreutilspaquete. Uno puede pensar que una herramienta adicional es totalmente excesiva, ya que podemos almacenar la salida de check_ipen una variable y reutilizarla condicionalmente, como en la respuesta mencionada:

if addr=$(check_ip); then
    echo "$addr" | update_bind9
fi

La condición puede ser [ -n "$addr" ]cualquiera; Lo importante es que usamos una variable. Un código como el anterior puede resolver su problema, pero en general presenta al menos tres problemas. Supongamos command1 | command2en lugar de check_ip | update_bind9. La solución se generaliza a:

if foo=$(command1); then
    echo "$foo" | command2
fi

Y luego:

  1. foo=$(command1)eliminará todas las nuevas líneas finales de la salida de command1. Entonces echo "$foo"(oprintf … "$foo") agregará exactamente un carácter de nueva línea (o un número fijo de ellos, respectivamente). Por este motivo, command2es posible que no obtenga el resultado exacto de command1.

  2. command1puede producir una salida que contenga caracteres NUL. Bash no puede almacenar NUL en una variable (la mayoría de los shells no pueden; zsh sí). Si aparece NUL, command2no obtendrá el resultado exacto de command1.

  3. command1puede producir un flujo enorme o incluso interminable, por lo que puede que no sea posible almacenarlo en una variable.

Usar un archivo en lugar de la variable resuelve todos los problemas excepto el último. command1 | ifne command2es inmune a los tres problemas.

información relacionada