Ce
STR="Hello\nWorld"
echo $STR
produit en sortie
Hello\nWorld
au lieu de
Hello
World
Que dois-je faire pour avoir une nouvelle ligne dans une chaîne?
Note: Cette question ne concerne pas echo. Je connais echo -e
, mais je cherche une solution qui permette de passer une chaîne (qui inclut une nouvelle ligne) en tant qu'argument pour autres commandes ne disposant pas d'une option similaire à interpréter. \n
en nouvelles lignes.
La solution consiste à utiliser $'string'
, par exemple:
$ STR=$'Hello\nWorld'
$ echo "$STR"
Hello
World
Voici un extrait de la page de manuel 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.
Echo a tellement de vie et de périls que son utilisation ne devrait pas générer moins de 4 Go de mémoire. Sérieusement, les problèmes d’écho étaient la raison pour laquelle le processus de normalisation Unix avait finalement inventé l’utilitaire printf
, supprimant tous les problèmes.
Donc, pour obtenir une nouvelle ligne dans une chaîne:
FOO="hello
world"
BAR=$(printf "hello\nworld\n") # Alternative; note: final newline is deleted
printf '<%s>\n' "$FOO"
printf '<%s>\n' "$BAR"
Là! Aucun SYSV vs BSD ne fait écho à la folie, tout est clairement imprimé et supporte de manière entièrement portable les séquences d'échappement en C. Tout le monde s'il vous plaît utilisez printf
maintenant et ne jamais regarder en arrière.
Ce que j'ai fait sur la base des autres réponses était
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
Le problème n'est pas avec le shell. Le problème vient en réalité de la commande echo
et de l'absence de guillemets autour de l'interpolation de variable. Vous pouvez essayer d'utiliser echo -e
mais cela n'est pas pris en charge sur toutes les plateformes et l'une des raisons pour lesquelles printf
est maintenant recommandée pour la portabilité.
Vous pouvez également essayer d'insérer la nouvelle ligne directement dans votre script Shell (si un script est ce que vous écrivez) afin qu'il ressemble ...
#!/bin/sh
echo "Hello
World"
#EOF
ou équivalent
#!/bin/sh
string="Hello
World"
echo "$string" # note double quotes!
La seule alternative simple est de taper une nouvelle ligne dans la variable:
$ STR='new
line'
$ printf '%s' "$STR"
new
line
Oui, cela signifie écrire Enter si nécessaire dans le code.
Il existe plusieurs équivalents à un caractère new line
.
\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.
Mais tous ceux qui nécessitent "une interprétation" par un outil ( 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.
Et par conséquent, l'outil est nécessaire pour construire une chaîne avec une nouvelle ligne:
$ STR="$(printf 'new\nline')"
$ printf '%s' "$STR"
new
line
Dans certains coquillages, la séquence $' est une extension spéciale de Shell. Connu pour fonctionner en ksh93, bash et zsh:
$ STR=$'new\nline'
Bien entendu, des solutions plus complexes sont également possibles:
$ echo '6e65770a6c696e650a' | xxd -p -r
new
line
Ou
$ echo "new line" | sed 's/ \+/\n/g'
new
line
Je trouve le drapeau -e
élégant et simple
STR="Hello\nWorld"
echo -e $STR
# output
Hello
World
Si la chaîne est la sortie d'une autre commande, j'utilise simplement des guillemets
indexes_diff=$(git diff index.yaml)
echo "$indexes_diff"
Un $ juste avant les guillemets simples '...\n ...' comme suit, mais les guillemets doubles ne fonctionnent pas.
$ echo $'Hello\nWorld'
Hello
World
$ echo $"Hello\nWorld"
Hello\nWorld
Je ne suis pas un expert en bash, mais celui-ci a fonctionné pour moi:
STR1="Hello"
STR2="World"
NEWSTR=$(cat << EOF
$STR1
$STR2
EOF
)
echo "$NEWSTR"
J'ai trouvé cela plus facile de formater les textes.
Les plus difficiles qui ont juste besoin de la nouvelle ligne et méprisent le code multiligne qui rompt l’indentation pourraient faire:
IFS="$(printf '\nx')"
IFS="${IFS%x}"
Bash (et probablement d'autres coquilles) engloutit tous les retours à la ligne après le remplacement de la commande. Vous devez donc terminer la chaîne printf
par un caractère autre que de nouvelle ligne, puis le supprimer. Cela peut aussi facilement devenir un oneliner.
IFS="$(printf '\nx')" IFS="${IFS%x}"
Je sais que c’est deux actions au lieu d’une, mais mon indentation et ma portabilité OCD sont en paix à présent :) j’ai développé ce système pour pouvoir séparer les sorties séparées entre nouvelles lignes et j’ai finalement utilisé une modification qui utilise
\r
comme caractère final . Cela permet au fractionnement de la nouvelle ligne de fonctionner même pour la sortie dos se terminant par\r\n
.IFS="$(printf '\n\r')"
Je n'étais vraiment pas content des options ici. C'est ce qui a fonctionné pour moi.
str=$(printf "%s" "first line")
str=$(printf "$str\n%s" "another line")
str=$(printf "$str\n%s" "and another line")
Sur mon système (Ubuntu 17.10), votre exemple fonctionne comme vous le souhaitez, à la fois lorsque vous le saisissez à partir de la ligne de commande (dans sh
) et lorsqu'il est exécuté en tant que 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
Je suppose que cela répond à votre question: cela fonctionne. (Je n'ai pas essayé de comprendre des détails tels qu'à quel moment exactement la substitution du caractère de nouvelle ligne pour \n
se produit dans sh
).
Cependant, j’ai remarqué que ce même script se comporterait différemment lorsqu’il serait exécuté avec bash
et afficherait Hello\nWorld
à la place:
[bash]§ bash test-str.sh
Hello\nWorld
J'ai réussi à obtenir la sortie souhaitée avec bash
comme suit:
[bash]§ STR="Hello
> World"
[bash]§ echo "$STR"
Notez les guillemets autour de $STR
. Cela se comporte de manière identique s’il est enregistré et exécuté en tant que script bash
.
Ce qui suit donne également la sortie souhaitée:
[bash]§ echo "Hello
> World"