GNU/Linux >> Tutoriales Linux >  >> Linux

Iterar sobre líneas en lugar de palabras en un bucle for de script de shell

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

Linux
  1. Formato de fecha y hora para script o variable de shell de Linux

  2. Cómo buscar archivos usando expresiones regulares en el script de shell de Linux

  3. Script de shell de Linux para la copia de seguridad de la base de datos

  4. Comenzando por Loop desde el segundo elemento - Script de Shell

  5. Script de transliteración para shell de linux

Golpe para bucle

Comprender el bucle for en los scripts de Shell

Directrices de ejecución de scripts de Shell para novatos

12 ejemplos de Bash For Loop para su secuencias de comandos de Linux Shell

Bash Script for Loop explicado con ejemplos

Iterar sobre la variable $ PATH usando el script de shell