2011-10-04 9 views
9

Ho bisogno di leggere alcuni dati di configurazione in variabili di ambiente in uno script bash.bash coproc e uscita coproc rimanente

Il pattern "ovvio" (ma non corretto) è:

egrep "pattern" config-file.cfg | read VAR1 VAR2 VAR3 etc... 

Questo fallisce perché read viene eseguito in una subshell e quindi non può impostare le variabili nella shell chiamante. Così mi è venuta in mente come alternativa

coproc egrep "pattern" config-file.cfg 
read -u ${COPROC[0]} VAR1 VAR2 VAR3 etc... 

che funziona bene.

Per verificare cosa succede se il coprocesso restituisce più di una riga, ho provato questo:

coproc cat config-file.cfg 
read -u ${COPROC[0]} VAR1 VAR2 VAR3 etc... 

dove config-file.cfg contiene tre linee.

$ cat config-file.cfg 
LINE1 A1 B1 C1 
LINE2 A2 B2 C2 
LINE3 A3 B3 C3 

Mi aspettavo questo per elaborare la prima riga del file, seguita da una sorta di messaggio di errore "tubo rotto". Mentre lo ha effettuato il processo nella prima riga, non è stato visualizzato alcun messaggio di errore e non è stata eseguita alcuna coprocess.

Così ho poi provato il seguente in uno script:

$ cat test.sh 
coproc cat config-file.cfg 
read -u ${COPROC[0]} VAR1 VAR2 VAR3 VAR4 
echo $VAR1 $VAR2 $VAR3 $VAR4 
wait 
echo $? 

L'esecuzione:

$ bash -x test.sh 
+ read -u 63 VAR1 VAR2 VAR3 VAR4 
+ cat config-file.cfg 
LINE1 A1 B1 C1 
+ wait 
+ echo 0 
0 

Dove sono finiti i restanti due linee andare? Mi sarei aspettato che il "tubo rotto", o il wait da appendere poiché non c'era nulla da leggere le righe rimanenti, ma come si può vedere il codice di ritorno era zero.

+3

A meno che non manchi qualcosa, qualcosa come 'leggere VAR1 VAR2 VAR3 <<(egrep" modello "config-file.cfg)" sarebbe sufficiente, no? –

+0

@ShawnChin: sta ignorando la domanda. I coproc sono ottimi motivi per cui l'OP non deve spiegare prima – sehe

+1

Perdona la mia ignoranza. Ammetto che i coproc sono fantastici, ma il commento è stato una risposta al pensiero che i coproc potrebbero essere un overkill se si tratta semplicemente di evitare di leggere la corsa in sottotitoli e perdere i vars. Probabilmente mi sbaglio, come al solito. –

risposta

5

Come per i commenti sopra, è possibile utilizzare process substitution per ottenere proprio questo. In questo modo, read non viene eseguito in una subshell e le vars catturate saranno disponibili all'interno della shell corrente.

read VAR1 VAR2 VAR3 < <(egrep "pattern" config-file.cfg) 

"Se viene utilizzata la (lista) formano <, il file passato come argomento deve essere letto per ottenere l'output di lista" - che cosa "file passato come agrument" sono stanno parlando?

Questo è piuttosto criptico anche per me.Lo chapter on process substitution nella Guida di scripting di Bash avanzato ha una spiegazione più completa.

Il modo in cui lo vedo, quando viene utilizzata la sintassi <(cmd), l'uscita di cmd viene resa disponibile tramite una named pipe (o un file temporaneo) e la sintassi viene sostituita dal nome file della pipe/file. Quindi per l'esempio precedente, si finirebbe per essere equivalente a:

read VAR1 VAR2 VAR3 < /dev/fd/63 

dove /dev/fd/63 è la pipa denominata collegato al stdout di cmd.

+0

Perfetto, grazie! Ho seguito il link che hai fornito, ed è ora nella mia collezione di riferimento bash permanente :-) –

+0

Contento di poter aiutare :) –

2

Se ho capito bene la tua domanda (e spero non sto affermando l'ovvio), leggere legge una riga alla volta, come in:

$ read a b c < config-file.cfg && echo $? 
0 

o:

$ printf '%s\n%s\n' one two | { read; echo "$REPLY";} 
one 

$ echo ${PIPESTATUS[@]} 
0 0 

Per leggere tutti gli input avrete bisogno di un ciclo:

$ coproc cat config-file.cfg 
[1] 3460 

$ while read -u ${COPROC[0]} VAR1 VAR2 VAR3; do echo $VAR1 $VAR2 $VAR3; done 
LINE1 A1 B1 C1 
LINE2 A2 B2 C2 
LINE3 A3 B3 C3 
[1]+ Done     coproc COPROC cat config-file.cfg 

Solo per aggiungere che ciò è spiegato nello FAQ.

+1

No, capisco che 'read' legge una riga alla volta. Quello che stavo chiedendo era che cosa è successo alle linee bufferizzate quando ne leggevi solo una. Mi aspettavo un errore o mi sono impiccato, ma sono semplicemente scomparsi, che in realtà è quello che voglio, ma odio la "magia" che non capisco e non posso prevedere. –

+0

Il co-proc non aspetta solo che tu legga il suo input (proprio come un normale pipe), ma va in timeout. Considera quanto segue: '$ {echo 1; echo 2;} 2' e '$ {echo 1; echo 2;} | { leggere; echo $ RISPOSTA; } 1'. Dove sono andati 2? –

+0

Quindi, per riformulare la risposta: in questo caso il coprocesso esce quando vede un end-of-file sul suo input. Bart Shaefer ha scritto un tutorial molto bello sui co-processi, puoi trovarlo [qui] (http://www.zsh.org/mla/users/2011/msg00095.html). –

Problemi correlati