it-swarm-es.com

Cadena multilínea con espacio adicional (sangría preservada)

Quiero escribir algunos textos predefinidos en un archivo con lo siguiente:

text="this is line one\n
this is line two\n
this is line three"

echo -e $text > filename

Estoy esperando algo como esto:

this is line one
this is line two
this is line three

Pero conseguí esto:

this is line one
 this is line two
 this is line three

Estoy seguro de que no hay espacio después de cada \n, pero ¿cómo sale el espacio extra?

292
cizixs

Heredoc suena más conveniente para este propósito. Se utiliza para enviar varios comandos a un programa de intérprete de comandos como ex o cat

cat << EndOfMessage
This is line 1.
This is line 2.
Line 3.
EndOfMessage

La cadena después de << indica dónde detenerse.

Para enviar estas líneas a un archivo, usa:

cat > $FILE <<- EOM
Line 1.
Line 2.
EOM

También puedes almacenar estas líneas en una variable:

read -r -d '' VAR << EOM
This is line 1.
This is line 2.
Line 3.
EOM

Esto almacena las líneas a la variable llamada VAR.

Al imprimir, recuerde las citas alrededor de la variable, de lo contrario no verá los caracteres de nueva línea.

echo "$VAR"

Aún mejor, puedes usar la sangría para que se destaque más en tu código. Esta vez solo agregue un - después de << para detener la aparición de las pestañas.

read -r -d '' VAR <<- EOM
    This is line 1.
    This is line 2.
    Line 3.
EOM

Pero luego debe usar tabulaciones, no espacios, para la sangría en su código.

490
new-kid

Si estás tratando de convertir la cadena en una variable, otra forma fácil es algo como esto:

USAGE=$(cat <<-END
    This is line one.
    This is line two.
    This is line three.
END
)

Si sangra su cadena con pestañas (es decir, '\ t'), la sangría se eliminará. Si hace sangría con espacios, la sangría quedará en.

NOTA: Es es significativo que el último paréntesis de cierre está en otra línea. El texto END debe aparecer en una línea por sí mismo.

116
Andrew Miner

echo agrega espacios entre los argumentos pasados. $text está sujeto a expansión de variables y división de palabras, por lo que su comando echo es equivalente a

echo -e "this" "is" "line" "one\n" "this" "is" "line" "two\n"  ...

Puede ver que se agregará un espacio antes de "esto". Puede eliminar los caracteres de nueva línea y citar $text para conservar las nuevas líneas:

text="this is line one
this is line two
this is line three"

echo "$text" > filename

O puede usar printf, que es más robusto y portátil que echo:

printf "%s\n" "this is line one" "this is line two" "this is line three" > filename

En bash, que admite la expansión de llaves, incluso podría hacer:

printf "%s\n" "this is line "{one,two,three} > filename
66
Josh Jolly

en un script de bash los siguientes trabajos:

#!/bin/sh

text="this is line one\nthis is line two\nthis is line three"
echo $text > filename

alternativamente:

text="this is line one
this is line two
this is line three"
echo "$text" > filename

cat nombre de archivo da:

this is line one
this is line two
this is line three
35
Chris Maes

He encontrado más soluciones ya que quería tener cada línea correctamente sangrada:

  1. Puedes usar echo:

    echo    "this is line one"   \
        "\n""this is line two"   \
        "\n""this is line three" \
        > filename
    

    No funciona si pones "\n" justo antes de \ en el final de una línea.

  2. Alternativamente, puedes usar printf para una mejor portabilidad (se me ocurrió que tuve muchos problemas con echo):

    printf '%s\n' \
        "this is line one"   \
        "this is line two"   \
        "this is line three" \
        > filename
    
  3. Otra solución podría ser:

    text=''
    text="${text}this is line one\n"
    text="${text}this is line two\n"
    text="${text}this is line three\n"
    printf "%b" "$text" > filename
    

    o

    text=''
    text+="this is line one\n"
    text+="this is line two\n"
    text+="this is line three\n"
    printf "%b" "$text" > filename
    
  4. Otra solución se logra mezclando printf y sed.

    if something
    then
        printf '%s' '
        this is line one
        this is line two
        this is line three
        ' | sed '1d;$d;s/^    //g'
    fi
    

    No es fácil refactorizar el código con este formato, ya que codifica el nivel de sangrado en el código.

  5. Es posible usar una función auxiliar y algunos trucos de sustitución de variables:

    unset text
    _() { text="${text}${text+
    }${*}"; }
    # That's an empty line which demonstrates the reasoning behind 
    # the usage of "+" instead of ":+" in the variable substitution 
    # above.
    _ ""
    _ "this is line one"
    _ "this is line two"
    _ "this is line three"
    unset -f _
    printf '%s' "$text"
    
30
Mateusz Piotrowski

La siguiente es mi forma preferida de asignar una cadena multilínea a una variable (creo que se ve bien).

read -r -d '' my_variable << \
_______________________________________________________________________________

String1
String2
String3
...
StringN
_______________________________________________________________________________

El número de guiones bajos es el mismo (aquí 80) en ambos casos.

1

funcionará si lo pones de la siguiente manera:

AA='first line
\nsecond line 
\nthird line'
echo $AA
output:
first line
second line
third line
1
luk