Bash: odczytywanie danych wejściowych podczas pętli odczytu nie działa

14

Wydaje się, że odczyt danych w pętli odczytu nie działa

while read line
do
 echo "get some input from the user"
 read response
done < some_file.txt

wykonanie nie zatrzymuje się tak, jakby odczyt był poza pętlą. Dlaczego to? Czy istnieje obejście dotyczące odczytu danych wejściowych w pętli odczytu podczas odczytu?

właściwie właściwie
źródło

Odpowiedzi:

15

Problem polega na tym, że zarówno read linei read responseoczekuje (i pobiera) danych z stdin.
To pytanie na SO wyjaśnia część z linkiem do jeszcze więcej informacji.

tl; dr
Akceptowana odpowiedź sugeruje:

Odczyt ze sterującego urządzenia końcowego: read input </dev/tty

Nifle
źródło
16

pozwól wewnętrznemu poleceniu odczytu użyć stdin i użyj innego deskryptora pliku dla pętli while

while read -u 3 line; do
  read -p "get some input from the user" response
done 3< some_file.txt
Glenn Jackman
źródło
1

Nifle ma dokładnie rację. Jeśli jednak korzystasz z wielu terminali, musisz być konkretny.

Dla tych z Was, którzy pochodzą z Google, gratulujemy znalezienia tej strony. Jeśli trzeba robić żadnych danych wprowadzonych przez użytkownika podczas odczytu pętli while (obejmuje to rm -i, readczy cokolwiek innego), można określić, które rurę wejściową do użytku.

Oto fragment tego rozwiązania, którego użyłem:

#in declarations
thistty=$(tty)

lsuser -R LDAP -a home pgrp ALL 2>/dev/null | while read line
do
   homedir=$(echo $homedir | awk -F= '{print $2}')
   sudo rm -ir "$homedir" < $thistty
done
bgStack15
źródło
1

Dzięki Nifle! A także dzięki bgStack. Po wielu godzinach szukania wreszcie znalazłem odpowiedź! Świetnie !! Użyłem „echo $ (tty)” do wykrycia mojej ścieżki terminala lub po prostu traktujesz ją jako zmienną. Dla mnie był to inny przypadek użycia. U czytał plik i chciałby potwierdzić wykonanie. Może poniższy przykład pomaga komuś innemu.

#!/bin/bash

export terminal=$(tty)

cat file | while read val1 val2
do
   while true; 
            do
              read -p "would you like to XYZ" yn
              case $yn in
                        [Yy]* )     echo "# Move $val1 to $val2        #";break;;
                        [Nn]* )     echo "#---------no action----------#";break;;
                        * )         echo "# Please answer yes or no.   #";;
              esac
            done < $terminal
done
Micha
źródło
W moim przypadku miałem whileczytania z potoku ... a potem użyłem przekierowania czytać ze standardowego wejścia: read something < %terminal.
eftshift0