salto - ¿Cómo puedo tener una nueva línea en una cadena en sh?
saltos de linea en jquery (10)
Esta
STR="Hello/nWorld"
echo $STR
produce como salida
Hello/nWorld
en lugar de
Hello
World
¿Qué debo hacer para tener una nueva línea en una cadena?
Nota: Esta pregunta no es sobre eco . Soy consciente de echo -e
, pero estoy buscando una solución que permita pasar una cadena (que incluye una nueva línea) como argumento a otros comandos que no tienen una opción similar para interpretar las /n
''s como nuevas líneas.
La única alternativa simple es escribir una nueva línea en la variable:
$ STR=''new line'' $ printf ''%s'' "$STR" new line
Sí, eso significa escribir Ingrese donde sea necesario en el código.
Hay varios equivalentes a una
new line
caracteres./n ### A common way to represent a new line character. /012 ### Octal value of a new line character. /x0A ### Hexadecimal value of a new line character.
Pero todos aquellos requieren "una interpretación" por alguna herramienta ( POSIX printf ):
echo -e "new/nline" ### on POSIX echo, `-e` is not required. printf ''new/nline'' ### Understood by POSIX printf. printf ''new/012line'' ### Valid in POSIX printf. printf ''new/x0Aline'' printf ''%b'' ''new/0012line'' ### Valid in POSIX printf.
Y por lo tanto, se requiere la herramienta para construir una cadena con una nueva línea:
$ STR="$(printf ''new/nline'')" $ printf ''%s'' "$STR" new line
En algunas conchas, la secuencia $ '' es una expansión de concha especial. Conocido para trabajar en ksh93, bash y zsh:
$ STR=$''new/nline''
Por supuesto, también son posibles soluciones más complejas:
$ echo ''6e65770a6c696e650a'' | xxd -p -r new line
O
$ echo "new line" | sed ''s/ /+//n/g'' new line
A $ justo antes de las comillas simples ''... / n ...'' de la siguiente manera, sin embargo, las comillas dobles no funcionan.
$ echo $''Hello/nWorld''
Hello
World
$ echo $"Hello/nWorld"
Hello/nWorld
Aquellos exigentes que necesitan solo la nueva línea y desprecian el código multilínea que rompe la sangría, podrían hacer:
IFS="$(printf ''/nx'')"
IFS="${IFS%x}"
Bash (y probablemente otros shells) se traga todas las nuevas líneas finales después de la sustitución del comando, por lo que debe terminar la cadena printf
con un carácter que no sea newline y luego borrarlo. Esto también puede convertirse fácilmente en un oneliner.
IFS="$(printf ''/nx'')" IFS="${IFS%x}"
Sé que esto es dos acciones en lugar de una, pero mi sangrado y portabilidad OCD está en paz ahora :) Originalmente desarrollé esto para poder dividir la salida separada solo de nueva línea y terminé usando una modificación que usa
/r
como la terminación personaje. Eso hace que la división de nueva línea funcione incluso para la salida de dos que termina con/r/n
.
IFS="$(printf ''/n/r'')"
El eco es tan noventa y tan lleno de peligros que su uso debería resultar en volcados de núcleo no menos de 4 GB. En serio, los problemas de eco fueron la razón por la cual el proceso de Estandarización de Unix finalmente inventó la utilidad printf
, eliminando todos los problemas.
Así que para obtener una nueva línea en una cadena:
FOO="hello
world"
BAR=$(printf "hello/nworld/n") # Alternative; note: final newline is deleted
printf ''<%s>/n'' "$FOO"
printf ''<%s>/n'' "$BAR"
¡Ahí! Sin la locura por el eco de SYSV y BSD, todo se imprime perfectamente y es totalmente compatible con las secuencias de escape C. Todos, por favor, usen printf
ahora y nunca miren atrás.
El problema no es con la concha. El problema es en realidad con el comando echo
sí, y la falta de comillas dobles alrededor de la variable interpolación. Puede intentar usar echo -e
pero eso no es compatible con todas las plataformas, y una de las razones por las que se recomienda printf
es la portabilidad.
También puedes probar e insertar la nueva línea directamente en tu script de shell (si un script es lo que estás escribiendo) para que se vea como ...
#!/bin/sh
echo "Hello
World"
#EOF
o equivalente
#!/bin/sh
string="Hello
World"
echo "$string" # note double quotes!
En mi sistema (Ubuntu 17.10), su ejemplo funciona como se desea, tanto cuando se escribe desde la línea de comandos (en sh
) como cuando se ejecuta como un script sh
:
[bash]§ sh
$ STR="Hello/nWorld"
$ echo $STR
Hello
World
$ exit
[bash]§ echo "STR=/"Hello/nWorld/"
> echo /$STR" > test-str.sh
[bash]§ cat test-str.sh
STR="Hello/nWorld"
echo $STR
[bash]§ sh test-str.sh
Hello
World
Supongo que esto responde a tu pregunta: simplemente funciona. (No he intentado averiguar detalles como en qué momento exactamente la sustitución del carácter de nueva línea por /n
ocurre en sh
).
Sin embargo, me di cuenta de que este mismo script se comportaría de manera diferente cuando se ejecutara con bash
y que en su lugar imprimiría Hello/nWorld
:
[bash]§ bash test-str.sh
Hello/nWorld
He logrado obtener la salida deseada con bash
siguiente manera:
[bash]§ STR="Hello
> World"
[bash]§ echo "$STR"
Tenga en cuenta las comillas dobles alrededor de $STR
. Esto se comporta de manera idéntica si se guarda y se ejecuta como un script bash
.
Lo siguiente también da el resultado deseado:
[bash]§ echo "Hello
> World"
La solución es usar $''string''
, por ejemplo:
$ STR=$''Hello/nWorld''
$ echo "$STR"
Hello
World
Aquí hay un extracto de la página del manual de Bash:
Words of the form $''string'' are treated specially. The word expands to
string, with backslash-escaped characters replaced as specified by the
ANSI C standard. Backslash escape sequences, if present, are decoded
as follows:
/a alert (bell)
/b backspace
/e
/E an escape character
/f form feed
/n new line
/r carriage return
/t horizontal tab
/v vertical tab
// backslash
/' single quote
/" double quote
/nnn the eight-bit character whose value is the octal value
nnn (one to three digits)
/xHH the eight-bit character whose value is the hexadecimal
value HH (one or two hex digits)
/cx a control-x character
The expanded result is single-quoted, as if the dollar sign had not
been present.
A double-quoted string preceded by a dollar sign ($"string") will cause
the string to be translated according to the current locale. If the
current locale is C or POSIX, the dollar sign is ignored. If the
string is translated and replaced, the replacement is double-quoted.
Lo que hice en base a las otras respuestas fue
NEWLINE=$''/n''
my_var="__between eggs and bacon__"
echo "spam${NEWLINE}eggs${my_var}bacon${NEWLINE}knight"
# which outputs:
spam
eggs__between eggs and bacon__bacon
knight
Me parece que la bandera es elegante y directa.
STR="Hello/nWorld" echo -e $STR
#outputs Hello World
Si la cadena es la salida de otro comando, solo uso comillas
indexes_diff=$(git diff index.yaml) echo "$indexes_diff"
No soy un experto en bash, pero este me funcionó:
STR1="Hello"
STR2="World"
NEWSTR=$(cat << EOF
$STR1
$STR2
EOF
)
echo "$NEWSTR"
Me pareció más fácil formatear los textos.