Baca masukan pengguna di dalam loop

99

Saya memiliki skrip bash yang seperti berikut,

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

tetapi ini jelas tidak memberi saya hasil yang benar seperti ketika saya membaca di loop sementara mencoba membaca dari nama file file karena kemungkinan pengalihan I / O.

Adakah cara lain untuk melakukan hal yang sama?

w2lame
sumber
Hal yang sama terjadi ketika Anda mengganti pengguna di bash dan menjalankan perintah baca di bawah pengguna yang dialihkan dalam skrip
krupal

Jawaban:

106

Baca dari perangkat terminal pengendali:

read input </dev/tty

info lebih lanjut: http://compgroups.net/comp.unix.shell/Fixing-stdin-inside-a-redirected-loop

lembab
sumber
12
-1, karena ini akan menghindari pengalihan lainnya. Misalnya, bash yourscript < /foo/barakan menunggu input pengguna, ini hanya dapat diterima saat membaca sandi. Jawaban dari @GordonDavisson lebih disukai untuk semua kegunaan lainnya.
tiwo
56

Anda dapat mengarahkan stdin biasa melalui unit 3 untuk menyimpannya di dalam pipeline:

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

BTW, jika Anda benar-benar menggunakan catcara ini, gantilah dengan pengalihan dan semuanya menjadi lebih mudah:

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

Atau, Anda dapat menukar stdin dan unit 3 dalam versi itu - baca file dengan unit 3, dan biarkan stdin saja:

while read line <&3; do
    # read & use stdin normally inside the loop
    read input
    echo "$input"
done 3<notify-finished
Gordon Davisson
sumber
kenapa skrip keduamu tergantung?
Luca Borrione
2
@ LucaBorrione: Bagaimana Anda menggunakannya? Apakah menunggu Anda untuk memberikan masukan (catatan bahwa read linemembaca dari notify-finish, tetapi jika Anda hanya menjalankannya seperti yang tertulis read -u 3 inputmembaca dari konsol)?
Gordon Davisson
3

Sepertinya Anda membaca dua kali, pembacaan di dalam while loop tidak diperlukan. Selain itu, Anda tidak perlu menjalankan perintah cat:

while read input
do
    echo $input
done < filename
Hai Vu
sumber
4
Tujuan OP adalah agar pembacaan di dalam loop berasal dari pengguna, sedangkan yang di luar adalah untuk membaca dari file. Jadi, mereka memang menginginkan dua bacaan yang berbeda, dari dua sumber yang berbeda. Ini jelas baik dari teks pertanyaan (menggambarkan readperilaku batin sebagai "tidak benar [karena] mencoba membaca dari file filename") dan jawaban yang diterima.
Charles Duffy
3

Coba ubah loop seperti ini:

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

Tes unit:

for line in $(cat /etc/passwd); do
    read input
    echo $input;
    echo "[$line]"
done
dimba
sumber
@ w2lame Diuji lagi, ubah "while" loop menjadi "for" loop - bekerja untuk saya. Coba "sex -x" lihat dari mana asal kesalahan
dimba
4
jangan gunakan kucing, lihat jawaban dari Hai Vu
Fredrik Pihl
+1. Ini jauh lebih mudah diterapkan untuk kebutuhan spesifik saya daripada saran lain.
Nathan Wallace
1
Lihat Jangan Membaca Garis Dengan Untuk di wiki Wooledge. Juga, shellcheck.net memperingatkan SC2013
Charles Duffy
1

Saya telah menemukan parameter ini -u dengan read.

"-u 1" berarti "membaca dari 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)
xerostomus
sumber
-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
Munchk1n
sumber