Lire l'entrée utilisateur dans une boucle


99

J'ai un script bash qui est quelque chose comme suivre,

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

mais cela ne me donne clairement pas la bonne sortie car lorsque je lis dans la boucle while, il essaie de lire à partir du nom de fichier du fichier en raison de la redirection d'E / S possible.

Une autre façon de faire de même?


La même chose se produit lorsque vous changez d'utilisateur dans bash et exécutez la commande de lecture sous l'utilisateur commuté dans le script
krupal

Réponses:



56

Vous pouvez rediriger le stdin normal via l'unité 3 pour le conserver dans le pipeline:

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

BTW, si vous utilisez vraiment de catcette façon, remplacez-le par une redirection et les choses deviennent encore plus faciles:

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

Ou, vous pouvez permuter stdin et unité 3 dans cette version - lisez le fichier avec l'unité 3, et laissez simplement stdin seul:

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

pourquoi votre deuxième script est-il suspendu?
Luca Borrione

2
@LucaBorrione: Comment l'utilisez-vous? Attend-il que vous lui donniez une entrée (notez que la read linelecture à partir de la notification est terminée, mais si vous l'exécutez simplement comme écrit, la read -u 3 inputlecture à partir de la console)?
Gordon Davisson

3

Il semble que vous ayez lu deux fois, la lecture à l'intérieur de la boucle while n'est pas nécessaire. De plus, vous n'avez pas besoin d'appeler la commande cat:

while read input
do
    echo $input
done < filename

4
Le but de l'OP est que la lecture à l'intérieur de la boucle provienne de l'utilisateur, tandis que la lecture externe est de lire à partir du fichier. Ainsi, ils veulent légitimement deux lectures différentes, de deux sources différentes. Ceci est clair à la fois à partir du texte de la question (décrivant le readcomportement de l'intérieur comme "pas juste [parce que] il essaie de lire à partir du fichier filename") et de leur réponse acceptée.
Charles Duffy

3

Essayez de changer la boucle comme ceci:

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

Test de l'unité:

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

@ w2lame Testé à nouveau, changez la boucle «while» en boucle «for» - cela fonctionne pour moi. Essayez "sex -x" voir d'où vient l'erreur
dimba

4
n'utilisez pas de chat, voir la réponse de Hai Vu
Fredrik Pihl

+1. Cela a été beaucoup plus facile à mettre en œuvre pour mes besoins spécifiques que d'autres suggestions.
Nathan Wallace

1
Voir Ne pas lire les lignes avec pour sur le wiki Wooledge. En outre, shellcheck.net avertissement SC2013
Charles Duffy

1

J'ai trouvé ce paramètre -u avec read.

"-u 1" signifie "lire depuis 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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.