¿Cuál es el significado exacto de IFS = $ '\ n'?

124

Si el siguiente ejemplo, que establece la IFSvariable de entorno en un carácter de avance de línea ...

IFS=$'\n'
  • ¿Qué hace el signo de dólar media exactamente el ?
  • ¿Qué hace en este caso específico?
  • ¿Dónde puedo leer más sobre este uso específico (Google no permite caracteres especiales en las búsquedas y no sé qué buscar)?

Sé cuál es la IFSvariable de entorno y cuál es el \ncarácter (salto de línea), pero ¿por qué no usar la siguiente forma: IFS="\n"(que no funciona)?

Por ejemplo, si quiero recorrer cada línea de un archivo y quiero usar un ciclo for, podría hacer esto:

for line in (< /path/to/file); do
    echo "Line: $line"
done

Sin embargo, esto no funcionará correctamente a menos que IFSesté configurado en un carácter de avance de línea. Para que funcione, tendría que hacer esto:

OLDIFS=$IFS
IFS=$'\n'
for line in (< /path/to/file); do
    echo "Line: $line"
done
IFS=$OLDIFS

Nota: No necesito otra forma de hacer lo mismo, ya conozco muchas otras ... Solo tengo curiosidad por eso $'\n'y me pregunto si alguien podría darme una explicación al respecto.

Yanick Girouard
fuente

Respuestas:

161

Normalmente bashno interpreta secuencias de escape en literales de cadena. Entonces, si escribe \no "\n"o '\n', eso no es un salto de línea: es la letra n(en el primer caso) o una barra invertida seguida de la letra n(en los otros dos casos).

$'somestring'es una sintaxis para literales de cadena con secuencias de escape . Entonces '\n', a diferencia , en $'\n'realidad es un salto de línea.

sepp2k
fuente
2
No es exactamente así: \nes solo una letra (escapado) n. Tienes razón en eso '\n'y tienes una "\n"reacción violenta seguida de n.
Roman Cheplyaka
15
Tenga en cuenta que $'\n'es específico de bash: no funcionará en un shell POSIX ( /bin/sh). Para obtener el mismo efecto de una manera compatible con POSIX, puede escribir IFS=', luego presionar regresar para escribir un carácter de nueva línea real, luego escribir el cierre'
Richard Hansen
23
IFS=$(echo -e '\n')también debe hacerlo de una manera compatible con POSIX.
Vineet
12
@Vineet: me dio una pausa para disputar un comentario votado. Si bien esto es correcto para Posix, no funciona: los operadores de sustitución de comandos en bash eliminan todos los caracteres de nueva línea finales. Vea esto para más detalles .
Trauma digital
9
@ Digital Trauma Creo que ni siquiera es POSIX: -eno está definido y \nsin -etrabajos como una extensión XSI: pubs.opengroup.org/onlinepubs/9699919799/utilities/… . printf '\n'rocas;)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
20

Solo para dar al constructo su nombre oficial : las cadenas del formulario $'...'se denominan cadenas con comillas C de ANSI .

Es decir, como en las cadenas [ANSI] C, las secuencias de escape de reacción se reconocen y se expanden a su equivalente literal (consulte a continuación la lista completa de secuencias de escape compatibles).

Después de esta expansión, las $'...'cadenas se comportan de la misma manera que las '...'cadenas , es decir, se tratan como literales que NO están sujetos a ninguna [más] expansión de shell .

Por ejemplo, se $'\n'expande a un carácter de nueva línea literal, que es algo que un literal de cadena bash normal (si '...'o no "...") puede hacer. [1]

Otra característica interesante es que las cadenas entre comillas ANSI C pueden escapar '(comillas simples) ya\' que, '...'(cadenas entre comillas simples) no pueden:

echo $'Honey, I\'m home' # OK; this cannot be done with '...'

Lista de secuencias de escape compatibles :

Las secuencias de escape de barra invertida, si están presentes, se decodifican de la siguiente manera:

\ una alerta (campana)

\ b retroceso

\ e \ E un carácter de escape (no ANSI C)

\ f alimentación de formulario

\ n nueva línea

retorno de carro

\ t pestaña horizontal

\ v pestaña vertical

\ barra invertida

\' una frase

\ "comilla doble

\ nnn el carácter de ocho bits cuyo valor es el valor octal nnn (de uno a tres dígitos)

\ xHH el carácter de ocho bits cuyo valor es el valor hexadecimal HH (uno o dos dígitos hexadecimales)

\ uHHHH el carácter Unicode (ISO / IEC 10646) cuyo valor es el valor hexadecimal HHHH (de uno a cuatro dígitos hexadecimales)

\ UHHHHHHHH el carácter Unicode (ISO / IEC 10646) cuyo valor es el valor hexadecimal HHHHHHHH (de uno a ocho dígitos hexadecimales)

\ cx un carácter control-x

El resultado ampliado está entre comillas simples, como si el signo del dólar no hubiera estado presente.


[1] Sin embargo, puede insertar nuevas líneas reales en las cadenas '...' y "..."; es decir, puede definir cadenas que abarcan varias líneas.

mklement0
fuente
16

De http://www.linuxtopia.org/online_books/bash_guide_for_beginners/sect_03_03.html :

Las palabras en la forma "$ 'STRING'" se tratan de manera especial. La palabra se expande a una cadena, con los caracteres con barra invertida reemplazados según lo especificado por el estándar ANSI-C. Las secuencias de escape de barra invertida se pueden encontrar en la documentación de Bash.

Supongo que está obligando al script a escapar del avance de línea al estándar ANSI-C adecuado.

Brad Swerdfeger
fuente
8

Recuperar el IFS predeterminado, esto OLDIFS=$IFSno es necesario. Ejecute el nuevo IFS en subshell para evitar anular el IFS predeterminado:

ar=(123 321); ( IFS=$'\n'; echo ${ar[*]} )

Además, realmente no creo que recuperes completamente el viejo IFS. Debería doble citarlo para evitar saltos de línea como OLDIFS="$IFS".

Marek
fuente
2
Esta es una técnica realmente útil. Acabo de usarlo para un shell más limpio args=$(IFS='&'; echo "$*"). restaurar IFSde $' \t\n'una manera amigable con los Bourne no es una hazaña.
jeberle
Re Besides I don't really believe you recover the old IFS fully: la división de palabras se no lleva a cabo en el lado derecho de la asignación de variables (pero eliminación de comillas es), por lo que OLDIFS=$IFSy OLDIFS="$IFS"se comportan de la misma manera.
mklement0
3

Las cadenas entre comillas ANSI C son un punto clave. Gracias a @ mklement0.

Puede probar las cadenas entre comillas ANSI C con el comando od.

echo -n $'\n' | od -c
echo -n '\n' | od -c
echo -n $"\n" | od -c
echo -n "\n" | od -c

Salidas:

0000000  \n  
0000001

0000000   \   n   
0000002

0000000   \   n   
0000002

0000000   \   n   
0000002

Puede conocer el significado claramente por las salidas.

Escudo grande
fuente
-7

Es como recuperar el valor de una variable:

VAR='test'
echo VAR
echo $VAR

son diferentes, por lo que el signo de dólar básicamente evalúa el contenido.

Pieter
fuente
66
Esto no tiene nada que ver con las variables. $'FOO'(a diferencia de lo $FOOque no se trataba esta pregunta) es un literal de cadena. Si ejecuta echo $'VAR', verá que imprime la cadena VAR, no test.
sepp2k