Uso para
for l in $()
realiza división de palabras según IFS:
$ for l in $(printf %b 'a b\nc'); do echo "$l"; done
a
b
c
$ IFS=$'\n'; for l in $(printf %b 'a b\nc'); do echo "$l"; done
a b
c
IFS no tiene que retroceder si no se usa más tarde.
for l in $()
también realiza la expansión del nombre de la ruta:
$ printf %b 'a\n*\n' > file.txt
$ IFS=$'\n'
$ for l in $(<file.txt); do echo "$l"; done
a
file.txt
$ set -f; for l in $(<file.txt); do echo "$l"; done; set +f
a
*
Si IFS=$'\n'
, los saltos de línea se eliminan y contraen:
$ printf %b '\n\na\n\nb\n\n' > file.txt
$ IFS=$'\n'; for l in $(<file.txt); do echo "$l"; done
a
b
$(cat file.txt)
(o $(<file.txt)
) también lee todo el archivo en la memoria.
Uso de lectura
Sin -r, las barras invertidas se usan para la continuación de línea y se eliminan antes que otros caracteres:
$ cat file.txt
\1\\2\
3
$ cat file.txt | while read l; do echo "$l"; done
1\23
$ cat file.txt | while read -r l; do echo "$l"; done
\1\\2\
3
Los caracteres en IFS se eliminan desde el principio y el final de las líneas, pero no se colapsan:
$ printf %b '1 2 \n\t3\n' | while read -r l; do echo "$l"; done
1 2
3
$ printf %b ' 1 2 \n\t3\n' | while IFS= read -r l; do echo "$l"; done
1 2
3
Si la última línea no termina con una nueva línea, read le asigna l pero sale antes del cuerpo del ciclo:
$ printf 'x\ny' | while read l; do echo $l; done
x
$ printf 'x\ny' | while read l || [[ $l ]]; do echo $l; done
x
y
Si un bucle while está en una canalización, también está en una subcapa, por lo que las variables no son visibles fuera de ella:
$ x=0; seq 3 | while read l; do let x+=l; done; echo $x
0
$ x=0; while read l; do let x+=l; done < <(seq 3); echo $x
6
$ x=0; x=8 | x=9; echo $x
0
El for
loop no está diseñado para recorrer "líneas". En su lugar, recorre "palabras".
Terminología corta:"líneas" son cosas separadas por saltos de línea. "palabras" son cosas separadas por espacios (y saltos de línea, entre otros). en la jerga de bash, las "palabras" se denominan "campos".
La forma idiomática de recorrer las líneas es usar un while
bucle en combinación con read
.
ioscan -m dsf | while read -r line
do
printf '%s\n' "$line"
done
Tenga en cuenta que el ciclo while está en una subcapa debido a la tubería. Esto puede causar cierta confusión con el alcance variable. En bash, puede solucionar esto utilizando la sustitución de procesos.
while read -r line
do
printf '%s\n' "$line"
done < <(ioscan -m dsf)
ver también http://mywiki.wooledge.org/BashFAQ/024
El ciclo for divide las cosas para recorrer usando los caracteres en el $IFS
variable como separadores. IFS es la abreviatura de Separador de campo interno. Normalmente $IFS
contiene un espacio, una tabulación y una nueva línea. Eso significa el for
loop se repetirá sobre las "palabras", no sobre las líneas.
Si insiste en usar un ciclo for para recorrer las líneas, debe cambiar el valor de $IFS
a solo nueva línea. Pero si hace esto, debe guardar el valor anterior de $IFS
y restaurar eso después del ciclo, porque muchas otras cosas también dependen de $IFS
.
OLDIFS="$IFS"
IFS=$'\n' # bash specific
for line in $(ioscan -m dsf)
do
printf '%s\n' "$line"
done
IFS="$OLDIFS"
en shells POSIX, que no tienen comillas ANSI-C ($'\n'
), puedes hacerlo así:
IFS='
'
es decir:ponga una nueva línea real entre las comillas.
Alternativamente, puede usar una subcapa para contener el cambio a $IFS
:
(
# changes to variables in the subshell stay in the subshell
IFS=$'\n'
for line in $(ioscan -m dsf)
do
printf '%s\n' "$line"
done
)
# $IFS is not changed outside of the subshell
Pero tenga cuidado, el comando en el bucle puede depender de alguna configuración sensata para $IFS
. Entonces tienes que restaurar el $IFS
antes de ejecutar el comando y establecer de nuevo antes del siguiente ciclo o algo así. No recomiendo meterse con $IFS
. Demasiados comandos dependen de algunos valores sensatos en $IFS
y cambiarlo es una pesadilla interminable de búsqueda de errores oscuros.
Véase también:
- http://wiki.bash-hackers.org/syntax/ccmd/classic_for
- http://wiki.bash-hackers.org/commands/builtin/read
- http://miwiki.wooledge.org/IFS
- http://miwiki.wooledge.org/SubShell
- http://mywiki.wooledge.org/ProcessSubstitution