2013-10-24 15 views
46

Bash permette di utilizzare: cat <(echo "$FILECONTENT")Come reindirizzare l'input a un Bash while e preservare variabili dopo ciclo termina

Bash permette inoltre di utilizzare: while read i; do echo $i; done </etc/passwd

di combinare due precedenti questo può essere utilizzato: echo $FILECONTENT | while read i; do echo $i; done

Il problema con l'ultimo è che crea sub-shell e dopo il ciclo while non è più possibile accedere alla variabile i.

La mia domanda è:

come realizzare qualcosa di simile: while read i; do echo $i; done <(echo "$FILECONTENT") o in altre parole: Come posso essere sicuro che i sopravvive ciclo while?

Si prega di notare che sono a conoscenza di racchiudere while in {} ma questo non risolve il problema (immaginare che si desidera utilizzare il ciclo while in funzione e tornare i variabile)

+0

http://mywiki.wooledge.org/BashFAQ/024 – tripleee

+0

Correlati: https://stackoverflow.com/questions/37229058/append-to-an-array-variable-from-a-pipeline-command. Spiega tutte le opzioni tra cui la sostituzione di processo sotto menzionata e "lastpipe" e i loro pro e contro. –

+0

Correlati: [Una variabile modificata all'interno di un ciclo while non viene ricordata] (https://stackoverflow.com/questions/16854280/a-variable-modified-inside-a-while-loop-is-not-remembered). – codeforester

risposta

60

La notazione corretta per Process Substitution è:

while read i; do echo $i; done < <(echo "$FILECONTENT") 

l'ultimo valore di i assegnato nel ciclo è quindi disponibile quando il ciclo termina. Un'alternativa è:

echo $FILECONTENT | 
{ 
while read i; do echo $i; done 
...do other things using $i here... 
} 

Le parentesi sono un'operazione di I/O di raggruppamento e di per sé non crea una subshell. In questo contesto, fanno parte di una pipeline e pertanto vengono eseguiti come sottotitoli, ma è a causa dello |, non dello { ... }. Lo menzioni nella domanda. AFAIK, puoi fare un ritorno all'interno di questi all'interno di una funzione.


Bash fornisce anche la shopt integrato e una delle sue numerose opzioni è:

lastpipe

Se impostato, e il controllo dei job non è attivo, il guscio viene eseguito l'ultimo comando di un pipeline non eseguita in background nell'ambiente di shell corrente.

Così, utilizzando qualcosa di simile in uno script rende il modfied sum disponibili dopo il ciclo:

FILECONTENT="12 Name 
13 Number 
14 Information" 
shopt -s lastpipe # Comment this out to see the alternative behaviour 
sum=0 
echo "$FILECONTENT" | 
while read number name; do ((sum+=$number)); done 
echo $sum 

Fare questo nella riga di comando di solito corre fallo di 'controllo del lavoro non è attivo' (cioè, nella riga di comando, il controllo dei lavori è attivo). Provare questo senza usare uno script fallito.

Inoltre, come notato da Gareth Rees nel suo answer, a volte è possibile utilizzare un here string:

while read i; do echo $i; done <<< "$FILECONTENT" 

Questo non richiede shopt; potresti essere in grado di salvare un processo usando questo.

+0

Perdonami la mia ignoranza. So che questa è la soluzione giusta e l'ho contrassegnata come risposta, quindi ha funzionato per me. Ma ora quando corro 'mentre leggo i; fai eco $ i; fatto <<(cat/etc/passwd); echo $ i' Non ha restituito l'ultima riga due volte. Cosa sto facendo di sbagliato? –

+0

@WakanTanka: Ho dovuto sperimentare un po '... Credo che la risposta sia che la lettura in errore resetta 'i' a vuoto, quindi l'eco dopo il ciclo echeggia una riga vuota. –

+0

Complimenti per il riferimento di sostituzione del processo. Ero inconsapevole di – Atcold