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.