Tubo da B a D? - A&& B || C | D


14

Esiste un modo per riscrivere la struttura dei comandi in A && B || C | Dmodo che B o C sia reindirizzato in D?

Con il comando corrente vengono eseguiti solo B o entrambi C e D.

Per esempio:

inserisci qui la descrizione dell'immagine

Risposte:


31

Sì, in bash puoi usare le parentesi:

(A && B || C) | D

In questo modo l'output di A && B || Cverrà reindirizzato D.


6
Oppure A && (B || C) | D, se non vuoi che B, C o D
vengano

2
Puoi anche usare le parentesi in sh:)
EKon il

Non è chiaro se usare parentesi anziché parentesi graffe sia stata una decisione intenzionale (in tal caso, quali sono i vantaggi?) O solo una svista. Potresti spiegare?
Tom Fenech,

@TomFenech Parens fa sì che l'espressione venga eseguita in una sotto-shell, che è un (singolo) processo separato dal POV del resto dello script. Pertanto, indipendentemente dall'output dell'espressione all'interno di parentesi, verrà convogliato insieme. (Dato che Aè all'interno della subshell, anche questo include A.)
jpaugh

1
@jpaugh Penso che il tuo punto sull'isolamento sia buono, ma l'output verrebbe convogliato allo stesso modo quando si usano le parentesi graffe, no?
Tom Fenech,

14

Puoi scrivere questo come

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

Dici di voler correre Bo C, ma A && B || Cnon ci riesci. Se Ariesce, ma Bfunziona e fallisce, verrebbe eseguito C.

Nota 1: se in qualche modo riesci a garantire che abbia Bsempre successo e vuoi restare con una versione breve, allora opterei comunque

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

finita ( ... ), poiché quest'ultima impone inutilmente la creazione di una nuova subshell, che può o meno essere ottimizzata.

Nota 2: entrambe le forme presuppongono che Anon produca alcun output, il che è vero nel tuo esempio ma non necessariamente in generale. Questo può essere evitato da

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

Sei sicuro che { … }non imponga la creazione di una subshell a causa della pipe? Osservo il seguente comportamento: pgrep bashe pgrep bash | cated if true; then pgrep bash; fie { pgrep bash; }ho una linea di output; ( pgrep bash; )e ( pgrep bash; ) | cate { pgrep bash; } | cate if true; then pgrep bash; fi | cathanno due linee di output.
wchargin,

@wchargin ... | ...provoca la creazione di una subshell, il che è inevitabile. ( ... ), almeno in teoria, provoca la creazione di una sottostruttura aggiuntiva che { ...; }evita, ma è quello che intendevo con "può o non può essere ottimizzato": è possibile che in questo caso particolare, la shell capisca che non ha importanza, il l'effetto sarebbe lo stesso.
hvd,

5

La risposta dell'accettatore è corretta ma non copre il potenziale caso d'uso per non avere l'output di Acome input di D. Per ottenere ciò, avrai bisogno di un reindirizzamento dello stream in Abase alle tue esigenze.

  • Se si desidera eliminare Acomunque l'output di :

    { A >/dev/null && B || C; } | D
  • Se vuoi vedere l'output di Asul terminale:

    { A >/dev/tty && B || C; } | D
  • Se è necessario l'output di Acome input di un comando successivo, Eè necessario un gruppo di comandi aggiuntivo e il reindirizzamento dello stream:

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

Se tutto ciò ti sembra troppo arcano (come per me) ti consiglio di usare la speciale variabile shell per lo stato di uscita Ae lavorare con quello:

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

Se vuoi essere più conciso ma non troppo arcano, suggerisco questo:

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

(Vedi anche l'ultima parte della risposta di hvd che non ho notato quando ho scritto la mia risposta originale.)


La mia risposta lo copre. Vedi cosa ho inserito nella mia "Nota 2:", dove mi sono semplicemente allontanato Adalla pipeline.
hvd,

@hvd: hai ragione e grazie per avermi sottolineato quella parte della tua risposta! Ho modificato la mia richiesta e ti ho dato credito di conseguenza.
David Foerster,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.