Puede que tenga algo absolutamente incorrecto, pero me parece convincente que configurar IFS como uno de los comandos en la lista pre-do/done no tiene absolutamente ningún efecto.
El IFS externo (fuera del while
constructo) prevalece en todos los ejemplos que se muestran en el siguiente script..
¿Que está pasando aqui? ¿Tengo una idea equivocada de lo que hace IFS en esta situación? Esperaba que los resultados de la división de matriz fueran los que se muestran en la columna "esperado".
#!/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-----"
Salida:
----- -- -- -------- 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=" "
----- -- -- -------- ----- --------- -------
Respuesta aceptada:
(Lo siento, larga explicación)
Sí, el IFS
variable en while IFS=" " read; do …
no tiene efecto en el resto del código.
Precisemos primero que la línea de comando de shell presenta dos tipos diferentes de variables:
- variables de shell (que solo existen dentro de un shell y son locales para el shell)
- variables de entorno, que existen para cada proceso. Esos generalmente se conservan en
fork()
yexec()
, por lo que los procesos secundarios los heredan.
Cuando llamas a un comando con:
A=foo B=bar command
el comando se ejecuta dentro de un entorno donde (entorno) variable A
se establece en foo
y B
se establece en bar
. Pero con esta línea de comando, las variables de shell actuales A
y B
se dejan sin cambios .
Esto es diferente de:
A=foo; B=bar; command
Aquí, las variables de shell A
y B
están definidos y el comando se ejecuta sin variables de entorno A
y B
definido. Valores de A
y B
no son accesibles desde command
.
Sin embargo, si algunas variables de shell son export
-ed, las variables de entorno correspondientes se sincronizan con sus respectivas variables de shell. Ejemplo:
export A
export B
A=foo; B=bar; command
Con este código, ambos shell variables y el shell entorno las variables se establecen en foo
y bar
. Dado que las variables de entorno son heredadas por subprocesos, command
podrá acceder a sus valores.
Para regresar a su pregunta original, en:
IFS='a' read
solo read
Es afectado. Y de hecho, en este caso, read
no le importa el valor del IFS
variable. Utiliza IFS
solo cuando solicita que la línea se divida (y se almacene en varias variables), como en:
echo "a : b : c" | IFS=":" read i j k;
printf "i is '%s', j is '%s', k is '%s'" "$i" "$j" "$k"
IFS
no es utilizado por read
a menos que se llame con argumentos. (Editar: Esto no es exactamente cierto:los caracteres de espacio en blanco, es decir, espacio y tabulación, presentes en IFS
siempre se ignoran al principio/final de la línea de entrada. )