Si je comprends bien, je pense que vous voulez essentiellement parcourir les listes de valeurs, puis read
une autre dans la boucle.
Voici quelques options, 1 et 2 sont probablement les plus saines.
1. Émuler des tableaux avec des chaînes
Avoir des tableaux 2D serait bien, mais pas vraiment possible dans Bash. Si vos valeurs n'ont pas d'espaces, une solution de contournement pour les rapprocher consiste à coller chaque ensemble de trois nombres dans une chaîne et à diviser les chaînes à l'intérieur de la boucle:
for x in "1 2 3" "4 5 6"; do
read a b c <<< "$x";
read -p "Enter a number: " d
echo "$a - $b - $c - $d ";
done
Bien sûr, vous pouvez également utiliser un autre séparateur, par exemple for x in 1:2:3 ...
et IFS=: read a b c <<< "$x"
.
2. Remplacez le tuyau par une autre redirection pour libérer stdin
Une autre possibilité est d'avoir la read a b c
lecture d'un autre fd et de diriger l'entrée vers celle-ci (cela devrait fonctionner dans un shell standard):
while read a b c <&3; do
printf "Enter a number: "
read d
echo "$a - $b - $c - $d ";
done 3<<EOF
1 2 3
4 5 6
EOF
Et ici, vous pouvez également utiliser une substitution de processus si vous souhaitez obtenir les données d'une commande: while read a b c <&3; ...done 3< <(echo $'1 2 3\n4 5 6')
(la substitution de processus est une fonctionnalité bash / ksh / zsh)
3. Prenez plutôt la contribution de l'utilisateur de stderr
Ou, à l'inverse, en utilisant un tuyau comme dans votre exemple, mais avec l'entrée utilisateur read
de stderr
(fd 2) au lieu de stdin
la provenance du tuyau:
echo $'1 2 3\n4 5 6' |
while read a b c; do
read -u 2 -p "Enter a number: " d
echo "$a - $b - $c - $d ";
done
La lecture stderr
est un peu étrange, mais fonctionne en fait souvent dans une session interactive. (Vous pouvez également ouvrir explicitement /dev/tty
, en supposant que vous voulez réellement contourner toutes les redirections, c'est ce que des choses comme less
utilise pour obtenir l'entrée de l'utilisateur même lorsque les données y sont acheminées.)
Bien que l'utilisation de ce stderr
type puisse ne pas fonctionner dans tous les cas, et si vous utilisez une commande externe à la place read
, vous auriez au moins besoin d'ajouter un tas de redirections à la commande.
Voir aussi Pourquoi ma variable est-elle locale dans une boucle "en lecture", mais pas dans une autre boucle apparemment similaire? pour certains problèmes concernant ... | while
.
4. Découpez des parties d'un tableau selon vos besoins
Je suppose que vous pouvez également approximer un tableau 2D-ish en copiant des tranches d'un tableau unidimensionnel normal:
data=(1 2 3
4 5 6)
n=3
for ((i=0; i < "${#data[@]}"; i += n)); do
a=( "${data[@]:i:n}" )
read -p "Enter a number: " d
echo "${a[0]} - ${a[1]} - ${a[2]} - $d "
done
Vous pouvez également affecter ${a[0]}
etc. à a
, b
etc si vous voulez des noms pour les variables, mais Zsh le ferait beaucoup plus bien .
stderr
comme ça est un peu capricieux, mais j'ai le souvenir qu'un utilitaire le fait. Mais tout ce que je peux trouver maintenant, ce sont ceux qui ne font qu'utiliser/dev/tty
. Tant pis.<&2
(ainsi que</dev/tty
) évite de lire à partir du stdin du script. Cela ne fonctionnera pasprintf '682\n739' | ./script
. Notez également queread -p
ne fonctionne qu'en bash.while
boucle, donc vous ne pouvez pas vraiment utiliser le stdin du script de toute façon ...read -u
est aussi bash, mais peut être remplacé par des redirections, et<<<
dans le premier est également non standard, mais c'est un peu plus difficile à contourner.Il n'y en a qu'un
/dev/stdin
,read
lira partout où il est utilisé (par défaut).La solution consiste à utiliser un autre descripteur de fichier au lieu de 1 (
/dev/stdin
).De l'équivalent de code (en bash) à ce que vous avez publié [1] (regardez ci-dessous),
ajoutez simplement
0</dev/tty
(par exemple) pour lire à partir du "vrai" tty:À l'exécution:
Une autre alternative est d'utiliser
0<&2
(qui peut sembler étrange, mais qui est valide).Notez que la lecture de
/dev/tty
(également0<&2
) contournera le stdin du script, cela ne lira pas les valeurs de l'écho:Autres solutions
Ce qui est nécessaire est de rediriger une entrée vers un autre fd (descripteur de fichier).
Valide en ksh, bash et zsh:
Ou, avec exec:
Une solution qui fonctionne en sh (
<<<
ne fonctionne pas):Mais c'est probablement plus facile à comprendre:
1 Code plus simple
Votre code est:
Un code simplifié (en bash) est:
Qui, s'il est exécuté, imprime:
Ce qui montre simplement que le var d est lu à partir du même
/dev/stdin
.la source
Avec
zsh
, vous pouvez l'écrire à la place:Pour les tableaux 2D, voir également le
ksh93
shell:la source