Cómo agregar nuevas líneas en variables en script bash

64

Cuando lo hago

str="Hello World\n===========\n"

Me sale el \nimpreso también. ¿Cómo puedo tener nuevas líneas entonces?

Jiew Meng
fuente
1
Si bien las respuestas aquí son excelentes, en realidad creo que sería mejor usar una matriz para este tipo de cosas la mayor parte del tiempo.
evilsoup
Consulte también la pregunta Intentar incrustar nueva línea en una variable en bash .
HelloGoodbye

Respuestas:

73

En bashpuedes usar la sintaxis

str=$'Hello World\n===========\n'

Las comillas simples precedidas por a $son una nueva sintaxis que permite insertar secuencias de escape en cadenas.

También printfincorporado permite guardar la salida resultante en una variable

printf -v str 'Hello World\n===========\n'

Ambas soluciones no requieren una subshell.

Si en lo siguiente necesita imprimir la cadena, debe usar comillas dobles, como en el siguiente ejemplo:

echo "$str"

porque cuando imprime la cadena sin comillas, la nueva línea se convierte en espacios.

enzotib
fuente
1
¿Cómo se str=$'Hello World\n===========\n'llama la sintaxis ? sustitución variable?
zengr
55
@zengr: Se llama cita ANSI-C , y también es compatible con zshy ksh; sin embargo, NO es compatible con POSIX.
mklement0
44
@ mkelement0, proviene de ksh93, también es compatible con zsh, bash, mksh y FreeBSD sh, y su inclusión en la próxima revisión importante de POSIX está en discusión
Stéphane Chazelas
1
¿No parece funcionar con comillas dobles? por ejemplo str=$"My $PET eats:\n$PET food"? Este enfoque funciona para comillas dobles
Brad Parks
31

Puede poner nuevas líneas literales entre comillas simples (en cualquier shell de estilo Bourne / POSIX).

str='Hello World
===========
'

Para una cadena multilínea, aquí los documentos son a menudo convenientes. La cadena se alimenta como entrada a un comando.

mycommand <<'EOF'
Hello World
===========
EOF

Si desea almacenar la cadena en una variable, use el catcomando en una sustitución de comando. La sustitución del comando eliminará los caracteres de nueva línea al final de la cadena. Si desea retener las nuevas líneas finales, coloque un tapón al final y luego quítelo. En shells compatibles con POSIX, puede escribir str=$(cat <<'EOF'); str=${str%a}seguido del heredoc propiamente dicho, pero bash requiere que el heredoc aparezca antes del paréntesis de cierre.

str=$(cat <<'EOF'
Hello World
===========
a
EOF
); str=${str%a}

En ksh, bash y zsh, puede usar el $'…'formulario entre comillas para expandir los escapes de barra invertida dentro de las comillas.

str=$'Hello World\n===========\n'
Gilles 'SO- deja de ser malvado'
fuente
1
Estoy usando GNU bash 4.1.5, y str=$(cat <<'EOF')no funciona tal como está ... )Debe colocarse en la siguiente línea después del final del documento EOF... pero aun así, pierde la nueva línea final debido a Command Sustitución.
Peter.O
@fred Buenos puntos, he explicado sobre las nuevas líneas finales y el código mostrado que funciona en bash. Creo que es un error en bash, aunque para ser honesto al volver a leer la especificación POSIX, no está claro que el comportamiento sea obligatorio cuando el << está dentro de una sustitución de comando y el heredoc no.
Gilles 'SO- deja de ser malvado'
Buena cosa; para preservar las \ninstancias finales (y iniciales) bashal capturar un documento aquí en una variable, considere IFS= read -r -d '' str <<'EOF'...como una alternativa al enfoque de detención (vea mi respuesta).
mklement0
8

¿Estás usando "echo"? Prueba "echo -e".

echo -e "Hello World\n===========\n"
Miguel
fuente
2
Por cierto. No necesita la \ n final, porque echoagregará automáticamente una, a menos que especifique -n. (Sin embargo, la mayor parte de la pregunta es cómo obtener estas nuevas líneas en una variable).
Peter.O
+1 De todas las soluciones, esta es la más directa y simple.
Hai Vu
echo -e no funciona en OS X
Greg M. Krsak
2
@GregKrsak: En bash, echo -e hace el trabajo en OS X - eso es porque echoes una fiesta de orden interna (en lugar de un ejecutable externo) y que hace de soporte incorporado -e. (Como incorporado, debería funcionar en todas las plataformas en las que se ejecuta bash; por cierto, echo -efunciona en kshy zshtambién). Por el contrario, sin embargo, la utilidad externaecho en OS X /bin/echo- de hecho no es compatible -e.
mklement0
4

Si necesita nuevas líneas en su script muchas veces, puede declarar una variable global que contenga una nueva línea. De esa manera, puede usarlo en cadenas entre comillas dobles (expansiones variables).

NL=$'\n'
str="Hello World${NL} and here is a variable $PATH ===========${NL}"
pihentagy
fuente
¿Por qué $''requeriría una subshell?
Mat
Lo siento, leí mal una respuesta.
pihentagy
¿Podría pedir una explicación a los votantes negativos?
pihentagy
¡Agradable! Esto se puede incluir en variables usando comillas dobles, por ejemplo"My dog eats:${NL}dog food"
Brad Parks,
Esto funcionó para mí. Cuando se usa un script bash para componer una cadena que se copia automáticamente en el portapapeles para su posterior pegado en otro lugar, este enfoque funcionó para agregar nuevas líneas en la salida resultante.
Ville
3

De todas las discusiones, esta es la forma más simple para mí:

bash$ str="Hello World
==========="
bash$ echo "$str"
Hello World
===========

El comando echo debe usar comillas dobles .

kholis
fuente
3

Para complementar las excelentes respuestas existentes:

Si está usando bashy prefiere usar nuevas líneas reales para facilitar la lectura , reades otra opción para capturar un documento aquí en una variable que (como otras soluciones aquí) no requiere el uso de una subshell.

# Reads a here-doc, trimming leading and trailing whitespace.
# Use `IFS= read ...` to preserve it (the trailing \n, here).
read -r -d '' str <<'EOF'   # Use `IFS= read ...` to preserve the trailing \n
Hello World
===========
EOF
# Test: output the variable enclosed in "[...]", to show the value's boundaries.
$ echo "$str"
[Hello World
===========]
  • -rgarantiza que readno interprete la entrada (de forma predeterminada, trataría las barras invertidas especiales, pero eso rara vez se necesita).

  • -d ''establece el delimitador de "registro" en una cadena vacía, lo readque hace que lea toda la entrada de una vez (en lugar de solo una línea).

Tenga en cuenta que al dejar $IFS(el separador de campo interno) en su valor predeterminado $' \t\n'(un espacio, una pestaña, una nueva línea), cualquier espacio en blanco inicial y final se recorta del valor asignado a $str, que incluye la nueva línea final de here-doc.
(Tenga en cuenta que a pesar de que el cuerpo de aquí-doc comienza en la línea después del delimitador de inicio ( 'EOF'aquí), esto no contiene ningún líder de salto de línea).

Por lo general, este es el comportamiento deseado, pero si desea esa nueva línea final, use en IFS= read -r -d ''lugar de solo read -r -d '', pero tenga en cuenta que cualquier espacio en blanco inicial y final se conserva.
(Tenga en cuenta que anteponer IFS= directamente al readcomando significa que la asignación está vigente solo durante ese comando, por lo que no es necesario restaurar el valor anterior).


El uso de un documento aquí también le permite utilizar opcionalmente la sangría para activar la cadena de varias líneas para facilitar la lectura:

# Caveat: indentation must be actual *tab* characters - spaces won't work.
read -r -d '' str <<-'EOF' # NOTE: Only works if the indentation uses actual tab (\t) chars.
    Hello World
    ===========
EOF
# Output the variable enclosed in "[...]", to show the value's boundaries.
# Note how the leading tabs were stripped.
$ echo "$str"
[Hello World
===========]

Colocar -entre <<y el delimitador here-doc de apertura ( 'EOF', aquí) hace que los caracteres de tabulación iniciales se eliminen del cuerpo de here-doc e incluso del delimitador de cierre, pero tenga en cuenta que esto solo funciona con caracteres de tabulación reales , no espacios, así que si su el editor traduce las pulsaciones de teclas en espacios, se necesita trabajo adicional.

mklement0
fuente
-1

necesitas hacerlo de esta manera:

STR=$(echo -ne "Hello World\n===========\n")

Actualizar:

Como Fred lo señaló, de esta manera perderá "\ n" al final. Para asignar variables con secuencias de barra invertida expandidas, haga:

STR=$'Hello World\n===========\n\n'

probémoslo:

echo "[[$STR]]"

nos da ahora:

[[Hello World
===========

]]

Tenga en cuenta que $ '' es diferente de $ "". El segundo hace la traducción de acuerdo con la configuración regional actual. Para deital vea la sección CITA en man bash.

Michał Šrajer
fuente
-2
#!/bin/bash

result=""

foo="FOO"
bar="BAR"

result+=$(printf '%s' "$foo")$'\n'
result+=$(printf '%s' "$bar")$'\n'

echo "$result"
printf '%s' "$result"

salida:

FOO
BAR

FOO
BAR
vern
fuente
1
¿Por qué no simplemente result+=$foo$'\n'? $(printf %s "$foo")recortaría los caracteres de la nueva línea final en $foocaso de haberlos.
Stéphane Chazelas
No hay explicación para el código, de lo contrario, me parece bien.
Algo