¿Cuál es el significado de IFS = $ '\ n' en las secuencias de comandos bash?

163

Al comienzo de un script de shell bash se encuentra la siguiente línea:

IFS=$'\n'

¿Cuál es el significado detrás de esta colección de símbolos?

Abdul Al Hazred
fuente
3
Consulte también unix.stackexchange.com/questions/26784/understanding-ifs y las preguntas que cita.
Gilles
La sintaxis de vim resalta esto como un error para mí; ¿reparar?
theonlygusti
IFS=$'\n'es un bashism (+ otros shells, use ANSI-C Quoting , para soluciones ver stackoverflow.com/questions/10748703/…
pevik

Respuestas:

199

IFSsignifica "separador de campo interno". El shell lo utiliza para determinar cómo dividir las palabras, es decir, cómo reconocer los límites de las palabras.

Pruebe esto en un shell como bash (otros shells pueden manejar esto de manera diferente, por ejemplo zsh):

mystring="foo:bar baz rab"
for word in $mystring; do
  echo "Word: $word"
done

El valor predeterminado para IFSconsiste en caracteres de espacio en blanco (para ser precisos: espacio, tabulación y nueva línea). Cada carácter puede ser un límite de palabra. Entonces, con el valor predeterminado de IFS, se imprimirá el bucle anterior:

Word: foo:bar
Word: baz
Word: rab

En otras palabras, el shell piensa que el espacio en blanco es un límite de palabra.

Ahora, intente configurar IFS=:antes de ejecutar el bucle. Esta vez, el resultado es:

Word: foo
Word: bar baz rab

Ahora, el caparazón también se divide mystringen palabras, pero ahora, solo trata los dos puntos como el límite de la palabra.

El primer carácter de IFSes especial: se utiliza para delimitar palabras en la salida cuando se usa la $*variable especial (ejemplo tomado de la Guía avanzada de secuencias de comandos Bash , donde también puede encontrar más información sobre variables especiales como esa):

$ bash -c 'set w x y z; IFS=":-;"; echo "$*"'
w:x:y:z

Comparar con:

$ bash -c 'set w x y z; IFS="-:;"; echo "$*"'
w-x-y-z

Tenga en cuenta que en ambos ejemplos, la cáscara se seguirá considerando todos los personajes :, -y ;como límites de las palabras. Lo único que cambia es el comportamiento de $*.

Otra cosa importante a saber es cómo la llamada "IFS espacio en blanco" es tratado . Básicamente, tan pronto como IFSincluye espacios en blanco, los espacios en blanco iniciales y finales se eliminan de la cadena para dividirse antes de procesarlos y una secuencia de caracteres en blanco consecutivos también delimita los campos. Sin embargo, esto solo se aplica a los caracteres de espacios en blanco que están realmente presentes en IFS.

Por ejemplo, veamos la cadena "a:b:: c d "(espacio final y dos caracteres de espacio entre cy d).

  1. Con IFS=:ello se dividiría en cuatro campos: "a", "b", ""(cadena vacía) y " c d "(de nuevo, dos espacios entre cy d). Tenga en cuenta los espacios en blanco iniciales y finales en el último campo.
  2. Con IFS=' :', que se divide en cinco campos: "a", "b", ""(cadena vacía), "c"y "d". Sin espacios en blanco iniciales y finales en ningún lado.

Observe cómo los caracteres de espacio en blanco consecutivos múltiples delimitan dos campos en el segundo ejemplo, mientras que los dos puntos consecutivos múltiples no lo hacen (ya que no son caracteres de espacio en blanco).

En cuanto a IFS=$'\n', que es una ksh93sintaxis también apoyado por bash, zsh, mkshy FreeBSD sh(con variaciones entre todas las conchas). Citando la página de manual de bash:

Las palabras de la forma $ 'string' se tratan especialmente. La palabra se expande a "cadena", con los caracteres con barra invertida reemplazados según lo especificado por el estándar ANSI C.

\nes la secuencia de escape para una nueva línea, por lo que IFStermina configurada en un solo carácter de nueva línea.

Tblue
fuente
3
Esto es bueno, pero, en mi opinión, sería mucho mejor leer y comprender la especificación POSIX en lugar de la bashguía de secuencias de comandos, o lo que sea. En general, la información disponible en enlaces como este carece de manera importante. De todos modos, se pierden dos puntos cruciales con respecto a la división de shell: el globting y el espacio en blanco IFS.
mikeserv
@mikeserv Gracias, agregué información sobre el espacio en blanco de IFS. No sabía sobre eso. :)
Tblue
44
No es tan relevante, pero si tiene curiosidad, es posible que desee ver cómo unset IFSse comporta un shell de manera muy diferente IFS=. También el primer byte en IFS también es especial "${named_array[*]}", pero tampoco importa cuando no se
cita
Algunos puntos más: la división de 1 palabra, gobernada por, $IFSes una de las dos cosas principales que se realizan al expandir una variable sin comillas en el contexto de la lista (es la splitparte del split+globoperador). El otro es engorroso. Al usar la división de trabajo, generalmente necesita emitir set -fpara deshabilitar la globpieza.
Stéphane Chazelas
3
3- $IFStambién es usado por el readcomando incorporado
Stéphane Chazelas
22

Dentro de las comillas simples, algunos personajes son evaluados especialmente. Por ejemplo, \nse traduce a una nueva línea.

Entonces, esta línea particular asigna nueva línea a la variable IFS. IFS, a su vez, es una variable especial en bash: separador de campo interno. Como man bashdice,

se usa para dividir palabras después de la expansión y para dividir líneas en palabras con el readcomando incorporado. El valor por defecto es <space><tab><newline>.

choroba
fuente
55
+1 por mencionar dollared single quotescuál es diferente de las comillas simples.
Snowcrash
2
@Snowcrash +1 por decir +1 por mencionar las comillas simples que son diferentes de las comillas simples . Lo siento, no pude evitarlo :) ¡Pero en realidad es algo muy bueno señalarlo porque es importante!
Pryftan
1
@Pryftan +1 por +1 por +1 ... ya sabes ... es realmente importante.
0xc0de
@ 0xc0de Definitivamente de acuerdo! ¡Gracias por eso! :)
Pryftan
15

Para abreviar, IFS=$'\n'asigne nueva línea \na la variable IFS.

$'string'construct es un mecanismo de citas que se utiliza para decodificar ANSI C como secuencias de escape. Esta sintaxis viene de ksh93, y era portátil a la cáscara moderno como bash, zsh, pdksh, busybox sh.

POSIX no define esta sintaxis, pero se aceptó para el problema SUS 7 .

Cuonglm
fuente
-1

Preferí explicarlo $IFScon un ejemplo:
Suponga que desea cp o mv u otro proceso de archivo, IFS está vacío por defualt, cuando sus archivos tienen metacargos o espacio como:
Linux Administration.pdfo Free Software Fundation.ogg, claro, tendrá un problema, porque: Linux considere un Param separado y Administartion consideran un parámetro separado. Entonces bash tiene built-in variable, luego puede inicializar a IFS==$(echo -en "\n\b"), luego bash descarta cualquier meta char y espacio entre el nombre del archivo, por ejemplo:

#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
mymusicdir=~/test/dd
find $mymusicdir -name "*" -execdir rename 's/ /_/g' "{}" +
IFS=$SAVEIFS
Golfo pérsico
fuente