¿Tubería B a D? - A y B || C | re

14

¿Hay alguna manera de reescribir la estructura de comandos A && B || C | Dpara que B o C se canalicen a D?

Con el comando actual solo se ejecutan B o C y D.

Por ejemplo:

ingrese la descripción de la imagen aquí

Philip Kirkbride
fuente

Respuestas:

31

Sí, en bash puedes usar paréntesis:

(A && B || C) | D

De esta manera, la salida de A && B || Cse canalizará a D.

utopía
fuente
66
O A && (B || C) | D, si no desea que B, C o D se ejecuten cuando A falla
zwol
2
También puedes usar parens en sh:)
EKons
No está claro si usar paréntesis en lugar de llaves fue una decisión intencional (de ser así, ¿cuáles son los beneficios?) O simplemente un descuido. ¿Podrías explicar?
Tom Fenech
@TomFenech Parens hace que la expresión se ejecute en un sub-shell, que es un proceso (único) separado del POV del resto del script. Por lo tanto, sea cual sea el resultado de la expresión dentro de parens, se canalizará. (Dado que Aestá dentro del subshell, esto también incluye A).
jpaugh
1
@jpaugh Creo que su punto sobre el aislamiento es bueno, pero la salida se canalizaría de la misma manera cuando se usan llaves, ¿no?
Tom Fenech
14

Puedes escribir esto como

if A; then B; else C; fi | D

Dices que quieres ejecutar cualquiera Bo C, pero A && B || Cno lo logras. Si Atiene éxito, pero se Bejecuta y falla, se ejecutará C.

Nota 1: si de alguna manera puede garantizar que Bsiempre tenga éxito y quiera seguir con una versión corta, entonces aún optaría por

{ A && B || C; } | D

terminado ( ... ), ya que este último obliga innecesariamente a crear una nueva subshell, que puede optimizarse o no.

Nota 2: ambas formas asumen que Ano producen resultados, lo cual es cierto en su ejemplo, pero no necesariamente en general. Eso puede ser evitado por

A; if [ "$?" -eq 0 ]; then B; else C; fi | D
hvd
fuente
¿Está seguro de que { … }no obliga a crear una subshell debido a la tubería? Observo el siguiente comportamiento: pgrep bashy pgrep bash | caty if true; then pgrep bash; fiy { pgrep bash; }tengo una línea de salida; ( pgrep bash; )y ( pgrep bash; ) | caty { pgrep bash; } | caty if true; then pgrep bash; fi | cattienen dos líneas de salida.
wchargin
@wchargin ... | ...hace que se cree una subshell, eso es inevitable. ( ... ), al menos en teoría, hace que se cree un subshell adicional que { ...; }evita, pero eso es lo que quise decir con "puede o no optimizarse": es posible que en este caso particular, el shell se dé cuenta de que no importa, el El efecto sería el mismo.
hvd
5

La respuesta del aceptador es correcta pero no cubre el caso de uso potencial para no tener la salida de Acomo la entrada de D. Para lograrlo, necesitará una redirección de transmisión en Afunción de sus necesidades.

  • Si desea descartar la salida de Atodos modos:

    { A >/dev/null && B || C; } | D
  • Si desea ver la salida de Aen el terminal:

    { A >/dev/tty && B || C; } | D
  • Si necesita la salida de Acomo la entrada de un comando posterior E, necesitará un grupo de comando adicional y una redirección de flujo:

    { { A >&3 && B || C; } | D; } 3>&1 | E

Si todo esto le parece demasiado arcano (como a mí), le recomiendo que use la variable de shell especial para el estado de salida Ay trabaje con eso:

A
if [ $? -eq 0 ]; then
  B
else
  C
fi |
D

Si quieres ser más conciso pero no demasiado arcano, te sugiero esto:

A; { [ $? -eq 0 ] && B || C; } | D

(Vea también la última parte de la respuesta de hvd que no noté cuando escribí mi respuesta original).

David Foerster
fuente
Mi respuesta cubre eso. Vea lo que puse en mi "Nota 2:", donde simplemente me mudé Ade la tubería.
hvd
@hvd: ¡Estás en lo correcto y gracias por señalarme esa parte de tu respuesta! Modifiqué mi reclamo y le di crédito en consecuencia.
David Foerster