Bash: sostituzione di processo e stdin


13

La seguente riga è ovvia:

echo "bla" | foo | bar

Ma quelli sotto fanno lo stesso?

echo "bla" | bar <(foo)
echo "bla" | bar < <(foo)

Quale dei fooe barleggi "bla" di stdin e perché?

Voglio dire, ovviamente, posso solo codificarlo e verificarlo, ma non sono sicuro che sia un comportamento definito o sto sfruttando funzionalità su cui non dovrei fare affidamento.

Risposte:


9

Dipende dalla shell e non è documentato AFAICS. In kshe bash, nel primo caso, foocondivideranno lo stesso standard bar. Combatteranno per l'output di echo.

Quindi ad esempio in,

$ seq 10000 | paste - <(tr 1 X)'
1       X
2       X042
3       X043
4       X044
5       X045
[...]

Vedi prove che pasteleggono ogni altro blocco di testo seqdall'output mentre trlegge gli altri.

Con zsh, ottiene lo stdin esterno (a meno che non sia un terminale e la shell non sia interattiva nel qual caso viene reindirizzata /dev/null). ksh(dove ha avuto origine) zshe bashsono le uniche shell tipo Bourne con supporto per la sostituzione di processo AFAIK.

In echo "bla" | bar < <(foo), nota che lo barstdin sarà la pipe alimentata dall'output di foo. È un comportamento ben definito. In tal caso, sembra che foo's stdin è il tubo alimentato da echoin tutto ksh, zshe bash.

Se vuoi avere un comportamento coerente in tutte e tre le shell ed essere a prova di futuro poiché il comportamento potrebbe cambiare in quanto non è documentato, lo scriverei:

echo bla | { bar <(foo); }

Per essere sicuri foo, lo stdin è anche la pipa di echo(non riesco a capire perché, comunque, vorresti farlo). O:

echo bla | bar <(foo < /dev/null)

Per assicurarsi fooche non legge dalla pipe da echo. O:

{ echo bla | bar 3<&- <(foo <&3); } 3<&0

Avere lo foostdin dello stdin esterno come nelle versioni attuali di zsh.


"In quel caso, lo stdin di foo è la pipa alimentata dall'eco in tutto ksh, zsh e bash." L'hai testato a mano proprio ora o è documentato da qualche parte?
etam1024,

"Nel primo caso" nella prima riga si riferisce a `| pippo | bar` o `| bar <(pippo) `?
Volker Siegel,

4

echo "bla" | foo | bar: L'output di echo "bla"viene reindirizzato a foo, il cui output viene reindirizzato a bar.

echo "bla" | bar <(foo): Quello tubi l'uscita di echo "bla"a bar. Ma barviene eseguito con un argomento. L'argomento è il percorso del descrittore di file, a cui fooverrà inviato l'output di . Questo argomento si comporta come un file che contiene l'output di foo. Quindi, non è lo stesso.

echo "bla" | bar < <(foo): Si può presumere che l'output di echo "bla"debba essere inviato bare l'intera istruzione sia equivalente alla prima. Ma non è corretto. Si verifica quanto segue: poiché il reindirizzamento di input <viene eseguito dopo pipe ( |), lo sovrascrive . Quindi echo "bla"non viene convogliato al bar. Invece l'output di fooviene reindirizzato come input standard a bar. Per cancellare questo vedere il seguente comando e output:

$ echo "bla" | cat < <(echo "foo")
foo

Come vedi echo "bla"è sostituito da echo "foo".

Ora vedi questo comando:

$ echo "bar" | cat < <(awk '{printf "%s and foo", $0}')
bar and foo

Quindi echo "bar"viene reindirizzato a awk, che legge stdin e aggiunge la stringa and fooall'output. Questo output viene reindirizzato a cat.


E la mia domanda è: "Il fatto che awklegge" bar "è un comportamento definito?"
etam1024,

Sì. cmd1 < <(cmd2)si comporta come cmd2 | cmd1.
caos,

O cmd1 | cmd2 | cmd3è lo stesso dicmd1 | cmd3 < <(cmd2)
caos,

3
Se fosse Wikipedia, aggiungerei il tag "citazione necessaria" alle tue dichiarazioni :) Il punto centrale della mia domanda è che funziona come dici tu, ma non sono riuscito a trovare alcuna documentazione al riguardo.
etam1024,
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.