Comment ajouter des nouvelles lignes aux variables dans le script bash

64

Quand je fais

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

Je reçois aussi les \nimprimés. Comment puis-je avoir de nouvelles lignes alors?

Jiew Meng
la source
1
Bien que les réponses soient excellentes, je pense qu’en réalité vous feriez mieux d’utiliser un tableau pour ce genre de chose la plupart du temps.
Evilsoup
Voir aussi la question Essayer d'incorporer newline dans une variable dans bash .
HelloGoodbye

Réponses:

73

En bashvous pouvez utiliser la syntaxe

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

Les guillemets simples précédés de $est une nouvelle syntaxe permettant d'insérer des séquences d'échappement dans des chaînes.

Également printfintégré, permet d’enregistrer le résultat obtenu dans une variable

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

Les deux solutions ne nécessitent pas de sous-shell.

Si, dans ce qui suit, vous devez imprimer la chaîne, vous devez utiliser des guillemets, comme dans l'exemple suivant:

echo "$str"

parce que lorsque vous imprimez la chaîne sans guillemets, les nouvelles lignes sont converties en espaces.

enzotib
la source
1
Quelle est la syntaxe str=$'Hello World\n===========\n'appelée? substitution variable?
Zengr
5
@zengr: Cela s'appelle ANSI-C , mais il est aussi supporté dans zshet ksh; Cependant, il n'est pas compatible POSIX.
mklement0
4
@ mkelement0, il provient de ksh93, est également soutenu par zsh, bash, mksh et FreeBSD sh, et son inclusion dans la prochaine révision majeure de POSIX est en cours de discussion
Stéphane Chazelas le
1
Ne semble pas fonctionner avec des guillemets doubles? par exemple str=$"My $PET eats:\n$PET food"? Cette approche fonctionne pour les guillemets doubles
Brad Parks
31

Vous pouvez mettre les retours à la ligne littéraux entre guillemets simples (dans n’importe quel shell Bourne / style POSIX).

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

Pour une chaîne multiligne, les documents sont souvent pratiques. La chaîne est introduite en entrée d'une commande.

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

Si vous souhaitez stocker la chaîne dans une variable, utilisez la catcommande dans une substitution de commande. Le ou les caractères de nouvelle ligne à la fin de la chaîne seront supprimés par la substitution de commande. Si vous souhaitez conserver les nouvelles lignes définitives, placez un bouchon à la fin et éliminez-le ensuite. Dans les shells compatibles POSIX, vous pouvez écrire str=$(cat <<'EOF'); str=${str%a}suivi de l'hérédoc proprement dit, mais bash exige que l'hérédoc apparaisse avant la parenthèse fermante.

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

Dans ksh, bash et zsh, vous pouvez utiliser le $'…'formulaire cité pour développer des échappements de barre oblique inversée à l'intérieur des guillemets.

str=$'Hello World\n===========\n'
Gilles, arrête de faire le mal
la source
1
J'utilise GNU bash 4.1.5 et str=$(cat <<'EOF')ne fonctionne pas tel quel. Il )doit être placé sur la ligne suivante après la fin du document EOF.. mais malgré cela, il perd le retour à la ligne suivant en raison de la commande Substitution.
Peter.O
@fred Bons points, j'ai déjà expliqué les nouvelles lignes de fin et le code indiqué qui fonctionne sous bash. Je pense que c'est un bug dans bash, bien que pour être honnête après avoir relu la spécification POSIX, je ne vois pas clairement que le comportement est obligatoire lorsque le << se trouve à l'intérieur d'une substitution de commande et que l'heredoc ne l'est pas.
Gilles 'SO- arrête d'être méchant'
Super trucs; pour conserver les \ninstances de fin (et principales) bashlors de la capture d'un here-doc dans une variable, considérez IFS= read -r -d '' str <<'EOF'...comme une alternative à l'approche par le bouchon (voir ma réponse).
mklement0
8

Utilisez-vous "echo"? Essayez "echo -e".

echo -e "Hello World\n===========\n"
Mike
la source
2
BTW. \ N n'est pas nécessaire, car vous echoen ajouterez automatiquement un, sauf si vous spécifiez -n. (Cependant, le principal problème de la question est de savoir comment obtenir ces nouvelles lignes dans une variable).
Peter.O
+1 De toutes les solutions, celle-ci est la plus directe et la plus simple.
Hai Vu le
echo -e ne fonctionne pas sous OS X
Greg M. Krsak
2
@GregKrsak: En bash, echo -e fait le travail sur OS X - c'est parce que echoest une fête builtin (plutôt que d' un exécutable externe) et que le soutien ne builtin -e. (En builtin, il devrait fonctionner sur toutes les plates - formes qui bash fonctionne sur, soit dit en passant, echo -etravaille kshet zshaussi). En revanche, l’ utilitaire externeecho sous OS X - /bin/echo- n’est en effet pas pris en charge -e.
mklement0
4

Si vous avez souvent besoin de nouvelles lignes dans votre script, vous pouvez déclarer une variable globale contenant une nouvelle ligne. De cette façon, vous pouvez l'utiliser dans des chaînes entre guillemets (extensions de variable).

NL=$'\n'
str="Hello World${NL} and here is a variable $PATH ===========${NL}"
pihentagy
la source
Pourquoi aurait $''besoin d'un sous-shell?
Mat
Désolé, j'ai mal interprété une réponse.
pihentagy
Pourrais-je demander une explication aux votants descendants?
pihentagy
Agréable! Cela peut être inclus dans les variables à l'aide de guillemets doubles, par exemple"My dog eats:${NL}dog food"
Brad Parks
Cela a fonctionné pour moi. Lors de l'utilisation d'un script bash pour composer une chaîne qui est automatiquement copiée dans le Presse-papiers pour un collage ultérieur, cette approche a fonctionné pour l'ajout de nouvelles lignes dans la sortie résultante.
Ville
3

De toute discussion, voici le moyen le plus simple pour moi:

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

La commande echo doit utiliser des guillemets doubles .

kholis
la source
3

Pour compléter les grandes réponses existantes:

Si vous utilisez bashet préférez utiliser de nouvelles lignes réelles pour des raisons de lisibilité , readune autre option est de capturer un document here dans une variable , qui (comme les autres solutions ici) ne nécessite pas l'utilisation d'un sous-shell.

# 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
===========]
  • -rgarantit que readn'interprète pas l'entrée (par défaut, les barres obliques inverses sont traitées comme telles, mais cela est rarement nécessaire).

  • -d ''définit le délimiteur "record" sur une chaîne vide, ce readqui entraîne la lecture complète de l' entrée en une seule fois (au lieu d'une seule ligne).

Notez qu'en laissant $IFS(le séparateur de champ interne) sa valeur par défaut $' \t\n'(un espace, un onglet, une nouvelle ligne), tous les espaces de début et de fin sont supprimés de la valeur affectée $str, ce qui inclut le retour à la ligne arrière du doc-doc.
(Notez que même si le corps de l'ici-doc commence sur la ligne après le délimiteur de départ ( 'EOF'ici), il ne pas contenir un premier saut de ligne).

Il s'agit généralement du comportement souhaité, mais si vous souhaitez utiliser ce retour à la ligne final, utilisez IFS= read -r -d ''plutôt que simplement read -r -d '', mais notez que tous les espaces de début et de fin sont ensuite conservés.
(Notez que l'ajout IFS= direct directement à la readcommande signifie que l'affectation est effective uniquement pendant cette commande. Il n'est donc pas nécessaire de restaurer la valeur précédente.)


L'utilisation d'un document ici vous permet également d' utiliser éventuellement l'indentation pour définir la chaîne multiligne aux fins de lisibilité:

# 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
===========]

Le placement -entre <<et le délimiteur here-doc d’ouverture ( 'EOF', ici) entraîne la suppression des caractères de tabulation principaux du corps de cet document et même du délimiteur de fermeture, mais notez que cela ne fonctionne qu'avec les caractères de tabulation réels , pas les espaces. l’éditeur traduit les tabulations en espaces, un travail supplémentaire est nécessaire.

mklement0
la source
-1

vous devez le faire de cette façon:

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

Mise à jour:

Comme Fred l'a souligné, vous perdrez ainsi le caractère "\ n". Pour affecter des variables avec des séquences de barres obliques inverses développées, procédez comme suit:

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

testons-le:

echo "[[$STR]]"

nous donne maintenant:

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

]]

Notez que $ '' est différent de $ "". La seconde effectue la traduction en fonction de la localisation actuelle. Pour deital, voir la section QUOTING en man bash.

Michał Šrajer
la source
-2
#!/bin/bash

result=""

foo="FOO"
bar="BAR"

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

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

sortie:

FOO
BAR

FOO
BAR
vern
la source
1
Pourquoi pas simplement result+=$foo$'\n'? $(printf %s "$foo")découperait les derniers caractères de nouvelle ligne dans le $foocas échéant.
Stéphane Chazelas
Il n'y a pas d'explication pour le code, sinon ça me va.
Quelque chose de quelque chose