Leggi l'input dell'utente all'interno di un ciclo


99

Sto avendo uno script bash che è qualcosa come seguire,

cat filename | while read line
do
    read input;
    echo $input;
done

ma questo chiaramente non mi sta dando l'output corretto poiché quando leggo nel ciclo while cerca di leggere dal file nomefile a causa del possibile reindirizzamento I / O.

Qualche altro modo per fare lo stesso?


La stessa cosa accade quando
cambi

Risposte:


106

Leggere dal dispositivo terminale di controllo:

read input </dev/tty

maggiori informazioni: http://compgroups.net/comp.unix.shell/Fixing-stdin-inside-a-redirected-loop


12
-1, poiché ciò aggirerà qualsiasi altro reindirizzamento. Ad esempio, bash yourscript < /foo/barattenderà l'input dell'utente, questo è accettabile solo durante la lettura delle password. La risposta di @GordonDavisson è preferibile per tutti gli altri usi.
tiwo

56

Puoi reindirizzare lo stdin regolare attraverso l'unità 3 per mantenerlo all'interno della pipeline:

{ cat notify-finished | while read line; do
    read -u 3 input
    echo "$input"
done; } 3<&0

A proposito, se stai davvero usando in catquesto modo, sostituiscilo con un reindirizzamento e le cose diventano ancora più semplici:

while read line; do
    read -u 3 input
    echo "$input"
done 3<&0 <notify-finished

Oppure puoi scambiare stdin e unità 3 in quella versione: leggi il file con l'unità 3 e lascia solo stdin:

while read line <&3; do
    # read & use stdin normally inside the loop
    read input
    echo "$input"
done 3<notify-finished

perché la tua seconda sceneggiatura è in sospeso?
Luca Borrione

2
@LucaBorrione: come lo usi? Sta aspettando che tu gli dia input (nota che read linesta leggendo da notificare-finito, ma se lo esegui come scritto read -u 3 inputsta leggendo dalla console)?
Gordon Davisson

3

Sembra che tu abbia letto due volte, la lettura all'interno del ciclo while non è necessaria. Inoltre, non è necessario richiamare il comando cat:

while read input
do
    echo $input
done < filename

4
L'obiettivo dell'OP è che la lettura all'interno del ciclo provenga dall'utente, mentre quella esterna è leggere dal file. Pertanto, vogliono legittimamente due letture diverse, da due fonti diverse. Questo è chiaro sia dal testo della domanda (che descrive il readcomportamento dell'interlocutore come "non corretto [perché] cerca di leggere dal file filename") e dalla risposta accettata.
Charles Duffy

3

Prova a cambiare il ciclo in questo modo:

for line in $(cat filename); do
    read input
    echo $input;
done

Test unitario:

for line in $(cat /etc/passwd); do
    read input
    echo $input;
    echo "[$line]"
done

@ w2lame Testato di nuovo, cambia "while" loop in "for" loop - funziona per me. Prova "sesso -x" per vedere da dove viene l'errore
dimba

4
non usare gatto, vedi risposta di Hai Vu
Fredrik Pihl

+1. Questo è stato molto più facile da implementare per le mie esigenze specifiche rispetto ad altri suggerimenti.
Nathan Wallace

1
Vedi Non leggere le righe con per sul wiki Wooledge. Inoltre, shellcheck.net avvertimento SC2013
Charles Duffy

1

Ho trovato questo parametro -u con read.

"-u 1" significa "leggi da stdin"

while read -r newline; do
    ((i++))
    read -u 1 -p "Doing $i""th file, called $newline. Write your answer and press Enter!"
    echo "Processing $newline with $REPLY" # united input from two different read commands.
done <<< $(ls)

-6
echo "Enter the Programs you want to run:"
> ${PROGRAM_LIST}
while read PROGRAM_ENTRY
do
   if [ ! -s ${PROGRAM_ENTRY} ]
   then
      echo ${PROGRAM_ENTRY} >> ${PROGRAM_LIST}
   else
      break
   fi
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.