J'ai peut-être quelque chose d'absolument faux, mais cela me semble convaincant, que définir IFS comme l'une des commandes dans la liste pre-do/done n'a absolument aucun effet.
L'IFS externe (en dehors du while
construct) prévaut dans tous les exemples présentés dans le script ci-dessous.
Que se passe t-il ici? Ai-je une mauvaise idée de ce que fait IFS dans cette situation ? Je m'attendais à ce que les résultats de la division du tableau soient comme indiqué dans la colonne "attendu".
#!/bin/bash
xifs() { echo -n "$(echo -n "$IFS" | xxd -p)"; } # allow for null $IFS
show() { x=($1)
echo -ne " (${#x[@]})t |"
for ((j=0;j<${#x[@]};j++)); do
echo -n "${x[j]}|"
done
echo -ne "t"
xifs "$IFS"; echo
}
data="a b c"
echo -e "----- -- -- t --------tactual"
echo -e "outside t IFS tinside"
echo -e "loop t Field tloop"
echo -e "IFS NR NF t Split tIFS (actual)"
echo -e "----- -- -- t --------t-----"
IFS=$' tn'; xifs "$IFS"; echo "$data" | while read; do echo -ne 't 1'; show "$REPLY"; done
IFS=$' tn'; xifs "$IFS"; echo "$data" | while IFS= read; do echo -ne 't 2'; show "$REPLY"; done
IFS=$' tn'; xifs "$IFS"; echo "$data" | while IFS=b read; do echo -ne 't 3'; show "$REPLY"; done
IFS=" "; xifs "$IFS"; echo "$data" | while read; do echo -ne 't 4'; show "$REPLY"; done
IFS=" "; xifs "$IFS"; echo "$data" | while IFS= read; do echo -ne 't 5'; show "$REPLY"; done
IFS=" "; xifs "$IFS"; echo "$data" | while IFS=b read; do echo -ne 't 6'; show "$REPLY"; done
IFS=; xifs "$IFS"; echo "$data" | while read; do echo -ne 't 7'; show "$REPLY"; done
IFS=; xifs "$IFS"; echo "$data" | while IFS=" " read; do echo -ne 't 8'; show "$REPLY"; done
IFS=; xifs "$IFS"; echo "$data" | while IFS=b read; do echo -ne 't 9'; show "$REPLY"; done
IFS=b; xifs "$IFS"; echo "$data" | while IFS= read; do echo -ne 't10'; show "$REPLY"; done
IFS=b; xifs "$IFS"; echo "$data" | while IFS=" " read; do echo -ne 't11'; show "$REPLY"; done
echo -e "----- -- -- t --------t-----"
Sortie :
----- -- -- -------- actual
outside IFS inside assigned
loop Field loop # inner
IFS NR NF Split IFS # expected IFS
----- -- -- -------- ----- # --------- --------
20090a 1 (3) |a|b|c| 20090a #
20090a 2 (3) |a|b|c| 20090a # |a b c| IFS=
20090a 3 (3) |a|b|c| 20090a # |a | c| IFS=b
20 4 (3) |a|b|c| 20 #
20 5 (3) |a|b|c| 20 # |a b c IFS=
20 6 (3) |a|b|c| 20 # |a | c| IFS=b
7 (1) |a b c| #
8 (1) |a b c| # |a|b|c| IFS=" "
9 (1) |a b c| # |a | c| IFS=b
62 10 (2) |a | c| 62 # |a b c| IFS=
62 11 (2) |a | c| 62 # |a|b|c| IFS=" "
----- -- -- -------- ----- --------- -------
Réponse acceptée :
(Désolé, longue explication)
Oui, l'IFS
variable dans while IFS=" " read; do …
n'a aucun effet sur le reste du code.
Précisons d'abord que la ligne de commande du shell comporte deux types de variables différents :
- variables shell (qui n'existent que dans un shell et sont locales au shell)
- variables d'environnement, qui existent pour chaque processus. Ceux-ci sont généralement conservés sur
fork()
etexec()
, donc les processus enfants en héritent.
Lorsque vous appelez une commande avec :
A=foo B=bar command
la commande est exécutée dans un environnement où la variable (d'environnement) A
est défini sur foo
et B
est défini sur bar
. Mais avec cette ligne de commande, les variables shell actuelles A
et B
sont laissés inchangés .
Ceci est différent de :
A=foo; B=bar; command
Ici, les variables shell A
et B
sont définis et la commande est exécutée sans les variables d'environnement A
et B
défini. Valeurs de A
et B
sont inaccessibles depuis la command
.
Cependant, si certaines variables shell sont export
-ed, les variables d'environnement correspondantes sont synchronisées avec leurs variables shell respectives. Exemple :
export A
export B
A=foo; B=bar; command
Avec ce code, les deux shell les variables et l'environnement shell les variables sont définies sur foo
et bar
. Puisque les variables d'environnement sont héritées par les sous-processus, command
pourront accéder à leurs valeurs.
Pour revenir à votre question initiale, dans :
IFS='a' read
seulement read
est affectée. Et en fait, dans ce cas, read
ne se soucie pas de la valeur de l'IFS
variable. Il utilise IFS
uniquement lorsque vous demandez à la ligne d'être scindée (et stockée dans plusieurs variables), comme dans :
echo "a : b : c" | IFS=":" read i j k;
printf "i is '%s', j is '%s', k is '%s'" "$i" "$j" "$k"
IFS
n'est pas utilisé par read
sauf s'il est appelé avec des arguments. (Modifier : Ce n'est pas tout à fait vrai :les caractères d'espacement, c'est-à-dire l'espace et la tabulation, sont présents dans IFS
sont toujours ignorés au début/à la fin de la ligne d'entrée. )