Come reindirizzare l'input a un ciclo while di Bash e preservare le variabili al termine del ciclo


88

Bash consente di utilizzare: cat <(echo "$FILECONTENT")

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

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

Il problema con l'ultimo è che crea una sotto-shell e dopo la fine del ciclo while inon è più possibile accedere alla variabile .

La mia domanda è:

Come ottenere qualcosa del genere: while read i; do echo $i; done <(echo "$FILECONTENT")o in altre parole: come posso essere sicuro che isopravvive al ciclo while?

Si prega di notare che sono consapevole di racchiudere l'istruzione while in {}ma questo non risolve il problema (immagina di voler usare il ciclo while nella funzione e la ivariabile di ritorno )



Correlati: stackoverflow.com/questions/37229058/… . Spiega tutte le opzioni, inclusa la sostituzione del processo menzionata di seguito lastpipeei loro pro e contro.
ivan_pozdeev

Risposte:


117

La notazione corretta per la sostituzione del processo è:

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

L'ultimo valore di iassegnato 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 graffe sono un'operazione di raggruppamento I / O e non creano esse stesse una subshell. In questo contesto, fanno parte di una pipeline e vengono quindi eseguiti come una subshell, ma è a causa di |, non di { ... }. Lo dici nella domanda. Per quanto ne so, puoi fare un ritorno da dentro questi dentro una funzione.


Bash fornisce anche il shoptbuiltin e una delle sue numerose opzioni è:

lastpipe

Se impostato e il controllo del lavoro non è attivo, la shell esegue l'ultimo comando di una pipeline non eseguita in background nell'ambiente shell corrente.

Pertanto, l'utilizzo di qualcosa di simile in uno script rende sumdisponibile la modifica 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

Farlo dalla riga di comando di solito viene eseguito in modo negativo con "il controllo del lavoro non è attivo" (ovvero, alla riga di comando, il controllo del lavoro è attivo). Il test senza utilizzare uno script non è riuscito.

Inoltre, come notato da Gareth Rees nella sua risposta , a volte puoi usare una stringa qui :

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

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


Perdonate la mia ignoranza. So che questa è la soluzione giusta e l'ho contrassegnata come risposta, quindi ha funzionato per me. Ma ora quando corro while read i; do echo $i; done < <(cat /etc/passwd); echo $iNon è tornato l'ultima riga due volte. Cosa sto facendo di sbagliato?
Wakan Tanka

@WakanTanka: ho dovuto sperimentare un po '... credo che la risposta sia che la lettura non riuscita si ripristina ia vuoto, quindi l'eco dopo il ciclo fa eco a una riga vuota.
Jonathan Leffler

1
Complimenti per il riferimento alla sostituzione del processo. Non ero a conoscenza.
Atcold

@ Wakan Tanka: ho ottenuto lo stesso risultato del tuo, io uso while read i; do x=$i; done < <(cat /etc/passwd); echo i=$i; echo x=$xlavorato, // forse quei giorni il comportamento di bash è cambiato?
yurenchen

Sei un salvavita! Sto cercando da ore una soluzione simile. Il tuo è l'unico che ha funzionato.
Pat


0

Questa funzione crea duplicati $ NUM volte di file jpg (bash)

function makeDups() {
NUM=$1
echo "Making $1 duplicates for $(ls -1 *.jpg|wc -l) files"
ls -1 *.jpg|sort|while read f
do
  COUNT=0
  while [ "$COUNT" -le "$NUM" ]
  do
    cp $f ${f//sm/${COUNT}sm}
    ((COUNT++))
  done
done
}
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.