Lesen Sie die Eingabe in Bash innerhalb einer while-Schleife


97

Ich habe ein Bash-Skript, das ungefähr so ​​aussieht:

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

Dies gibt mir jedoch eindeutig nicht die richtige Ausgabe, da beim Lesen in der while-Schleife aufgrund der möglichen E / A-Umleitung versucht wird, aus dem Dateinamen der Datei zu lesen.

Gibt es eine andere Möglichkeit, dasselbe zu tun?


Das Gleiche passiert, wenn Sie den Benutzer in Bash wechseln und den
Lesebefehl

Antworten:



55

Sie können den regulären Standard durch Einheit 3 ​​umleiten, um ihn in der Pipeline zu behalten:

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

Übrigens, wenn Sie catdiese Methode wirklich verwenden , ersetzen Sie sie durch eine Weiterleitung, und die Dinge werden noch einfacher:

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

Oder Sie können stdin und unit 3 in dieser Version austauschen - lesen Sie die Datei mit unit 3 und lassen Sie stdin einfach in Ruhe:

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

Warum hängt dein zweites Skript?
Luca Borrione

2
@ LucaBorrione: Wie benutzt du es? Wartet es darauf, dass Sie ihm eine Eingabe geben (beachten Sie, dass read linedas Lesen von Benachrichtigung beendet ist, aber wenn Sie es nur so ausführen, wie es geschrieben wurde, read -u 3 inputwird von der Konsole gelesen)?
Gordon Davisson

4

Versuchen Sie, die Schleife folgendermaßen zu ändern:

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

Gerätetest:

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

@ w2lame Erneut getestet, ändern Sie "while" -Schleife in "for" -Schleife - funktioniert für mich. Versuchen Sie "sex -x" zu sehen, woher der Fehler kommt
dimba

4
Verwenden Sie keine Katze, siehe Antwort von Hai Vu
Fredrik Pihl

+1. Dies war für meine spezifischen Bedürfnisse viel einfacher umzusetzen als andere Vorschläge.
Nathan Wallace

1
Siehe Lesen Sie keine Zeilen mit For im Wooledge-Wiki. Auch Shellcheck.net Warnung SC2013
Charles Duffy

3

Es sieht so aus, als würden Sie zweimal lesen. Das Lesen in der while-Schleife wird nicht benötigt. Außerdem müssen Sie den Befehl cat nicht aufrufen:

while read input
do
    echo $input
done < filename

4
Das Ziel des OP ist es, dass das Lesen innerhalb der Schleife vom Benutzer kommt, während das äußere darin besteht, aus der Datei zu lesen. Sie wollen also zu Recht zwei verschiedene Lesevorgänge aus zwei verschiedenen Quellen. Dies geht sowohl aus dem Text der Frage (die das readVerhalten des Inneren als "nicht richtig [weil] es versucht, aus der Datei zu lesen filename") als auch aus ihrer akzeptierten Antwort hervor.
Charles Duffy

1

Ich habe diesen Parameter -u mit read gefunden.

"-u 1" bedeutet "von stdin lesen"

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.