Hinzufügen von Zeilenumbrüchen zu Variablen im Bash-Skript

64

Wenn ich es tue

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

Ich bekomme das auch \nausgedruckt. Wie kann ich dann Newlines haben?

Jiew Meng
quelle
1
Obwohl die Antworten hier großartig sind, denke ich, dass Sie in der Realität die meiste Zeit besser dran sind, ein Array für diese Art von Dingen zu verwenden.
Evilsoup

Antworten:

73

In können bashSie die Syntax verwenden

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

Einfache Anführungszeichen, denen ein vorangestellt $ist, sind eine neue Syntax, mit der Escape-Sequenzen in Zeichenfolgen eingefügt werden können.

Außerdem printfkönnen Sie die resultierende Ausgabe in einer Variablen speichern

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

Beide Lösungen erfordern keine Unterschale.

Wenn Sie im Folgenden die Zeichenfolge drucken müssen, sollten Sie doppelte Anführungszeichen verwenden, wie im folgenden Beispiel:

echo "$str"

Wenn Sie die Zeichenfolge ohne Anführungszeichen drucken, werden Zeilenumbrüche in Leerzeichen umgewandelt.

Enzotib
quelle
1
Wie heißt die Syntax str=$'Hello World\n===========\n'? Variablensubstitution?
Zengr
5
@zengr: Es heißt ANSI-C- Anführungszeichen und wird auch in zshund unterstützt ksh. Es ist jedoch NICHT POSIX-konform.
mklement0
4
@ mkelement0, es kommt von ksh93, wird auch von zsh, bash, mksh und FreeBSD sh unterstützt, und die Aufnahme in die nächste größere Revision von POSIX wird diskutiert
Stéphane Chazelas
1
Scheint nicht mit doppelten Anführungszeichen zu arbeiten? zB str=$"My $PET eats:\n$PET food"? Dieser Ansatz funktioniert für doppelte Anführungszeichen
Brad Parks
31

Sie können wörtliche Zeilenumbrüche in einfache Anführungszeichen setzen (in jeder Bourne / POSIX-Shell).

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

Für eine mehrzeilige Zeichenfolge sind Dokumente hier häufig praktisch. Die Zeichenfolge wird als Eingabe für einen Befehl eingespeist.

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

Wenn Sie die Zeichenfolge in einer Variablen speichern möchten, verwenden Sie den catBefehl in einer Befehlsersetzung. Die Zeilenumbruchzeichen am Ende der Zeichenfolge werden durch die Befehlsersetzung entfernt. Wenn Sie die letzten Zeilenumbrüche beibehalten möchten, setzen Sie einen Stopfen an das Ende und entfernen Sie ihn anschließend. In POSIX-kompatiblen Shells können Sie schreiben, str=$(cat <<'EOF'); str=${str%a}gefolgt von dem eigentlichen Heredoc. Für Bash muss der Heredoc jedoch vor der schließenden Klammer stehen.

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

In ksh, bash und zsh können Sie $'…'das in Anführungszeichen gesetzte Formular verwenden, um die in Anführungszeichen gesetzten Schrägstriche zu erweitern.

str=$'Hello World\n===========\n'
Gilles 'SO - hör auf böse zu sein'
quelle
1
Ich verwende GNU Bash 4.1.5 und str=$(cat <<'EOF')arbeite nicht wie sie ist. Das )muss in die nächste Zeile nach dem Ende des Dokuments gestellt werden EOF. Trotzdem verliert es die nachgestellte Zeile aufgrund von Command Auswechslung.
Peter.O
@fred Gute Punkte, ich habe die nachfolgenden Zeilenumbrüche erklärt und Code gezeigt, der in bash funktioniert. Ich denke, es ist ein Fehler in der Bash, obwohl ich, um ehrlich zu sein, beim erneuten Lesen der POSIX-Spezifikation unklar finde, dass das Verhalten vorgeschrieben ist, wenn sich das << in einer Befehlsersetzung befindet und das Heredoc nicht.
Gilles 'SO- hör auf böse zu sein'
Tolles Zeug; Um nachgestellte (und führende) \nInstanzen bashbeim Erfassen eines Here-Docs in einer Variablen zu erhalten, sollten Sie IFS= read -r -d '' str <<'EOF'...eine Alternative zum Stopper-Ansatz in Betracht ziehen (siehe meine Antwort).
mklement0
8

Verwenden Sie "Echo"? Versuchen Sie es mit "echo -e".

echo -e "Hello World\n===========\n"
Mike
quelle
2
Übrigens. Sie brauchen das endgültige \ n nicht, da echoes automatisch hinzugefügt wird, sofern Sie nicht -n angeben. (Die Hauptfrage ist jedoch, wie diese Zeilen in eine Variable umgewandelt werden können.)
Peter.O
+1 Von allen Lösungen ist diese die direkteste und einfachste.
Hai Vu
echo -e funktioniert nicht unter OS X
Greg M. Krsak
2
@GregKrsak: In bash, echo -e funktioniert unter OS X - das echoliegt daran, dass eine Bash- Datei (und keine externe ausführbare Datei) eingebaut ist und diese eingebaute Datei unterstützt -e. (Als eingebautes Programm sollte es auf allen Plattformen funktionieren, auf denen bash ausgeführt wird. Funktioniert übrigens auch echo -ein kshund zsh). Im Gegensatz dazu jedoch das externe echoDienstprogramm auf O X - /bin/echo- in der Tat ist nicht unterstützt -e.
mklement0
4

Wenn Sie in Ihrem Skript häufig Zeilenumbrüche benötigen, können Sie eine globale Variable deklarieren, die einen Zeilenumbruch enthält. Auf diese Weise können Sie es in Strings mit doppelten Anführungszeichen (variable Erweiterungen) verwenden.

NL=$'\n'
str="Hello World${NL} and here is a variable $PATH ===========${NL}"
pihentagy
quelle
Warum sollte $''eine Unterschale benötigt werden?
Mat
Entschuldigung, ich habe eine Antwort falsch gelesen.
Mittwoch,
Könnte ich Downvoter um Erklärung bitten?
Mittwoch,
Nett! Dies kann in Variablen mit doppelten Anführungszeichen angegeben werden, z. B."My dog eats:${NL}dog food"
Brad Parks,
Das hat bei mir funktioniert. Bei Verwendung eines Bash-Skripts zum Zusammenstellen einer Zeichenfolge, die zum späteren Einfügen an einer anderen Stelle automatisch in die Zwischenablage kopiert wird, wurde mit diesem Ansatz in der resultierenden Ausgabe ein Zeilenumbruch eingefügt.
Ville vor
3

Nach allem, was ich diskutiere, ist dies der einfachste Weg für mich:

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

Der Echo- Befehl muss doppelte Anführungszeichen enthalten .

kholis
quelle
3

Ergänzend zu den bereits vorhandenen Antworten:

Wenn Sie mit bashund Sie lieber mit tatsächlichen Zeilenumbrüchen zur besseren Lesbarkeit , readist eine weitere Option für ein hier-doc in einer Variablen erfassen , die (wie auch andere Lösungen hier) nicht die Verwendung eines Sub - Shell benötigen.

# 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
===========]
  • -rStellt sicher, dass readdie Eingabe nicht interpretiert wird (standardmäßig werden Backslashes speziell behandelt, dies wird jedoch selten benötigt).

  • -d ''Setzt das Trennzeichen "record" auf eine leere Zeichenfolge, wodurch readdie gesamte Eingabe auf einmal gelesen wird (anstatt nur einer einzelnen Zeile).

Beachten Sie, dass durch Belassen $IFSder Standardeinstellung (internes Feldtrennzeichen) $' \t\n'(ein Leerzeichen, ein Tabulator, eine neue Zeile) alle führenden und nachfolgenden Leerzeichen von dem Wert, der zugewiesen wurde $str, abgeschnitten werden , einschließlich der nachfolgenden neuen Zeile des Dokuments.
(Beachten Sie, dass , obwohl die hier-doc Körper auf der Linie beginnt nach dem Anfangsbegrenzer ( 'EOF'hier), es ist nicht einen enthält führenden Newline).

In der Regel ist dies das gewünschte Verhalten. Wenn Sie diese nachgestellte Zeile jedoch verwenden möchten, verwenden Sie IFS= read -r -d ''anstelle von "nur" read -r -d ''. Beachten Sie jedoch, dass alle führenden und nachgestellten Leerzeichen dann beibehalten werden.
(Beachten Sie, dass das Voranstellen IFS= direkt vor dem readBefehl bedeutet, dass die Zuweisung nur während dieses Befehls wirksam ist, sodass der vorherige Wert nicht wiederhergestellt werden muss.)


Wenn Sie ein Here-Doc verwenden, können Sie auch optional Einrückungen verwenden , um die mehrzeilige Zeichenfolge aus Gründen der Lesbarkeit zu markieren:

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

Durch das Platzieren -zwischen <<und dem öffnenden Here-Doc-Trennzeichen ( 'EOF', hier) werden führende Tabulatorzeichen aus dem Here-Doc-Text und sogar dem schließenden Trennzeichen entfernt. Beachten Sie jedoch, dass dies nur mit tatsächlichen Tabulatorzeichen und nicht mit Leerzeichen funktioniert Editor übersetzt Tabulatortasten in Leerzeichen, zusätzliche Arbeit ist erforderlich.

mklement0
quelle
-1

du musst es so machen:

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

Aktualisieren:

Wie Fred darauf hingewiesen hat, verlieren Sie auf diese Weise das "\ n". Gehen Sie wie folgt vor, um Variablen mit erweiterten Backslash-Sequenzen zuzuweisen:

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

Lass es uns testen:

echo "[[$STR]]"

gibt uns jetzt:

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

]]

Beachten Sie, dass sich $ '' von $ "" unterscheidet. Die zweite Option übersetzt nach dem aktuellen Gebietsschema. Für Gottheiten siehe Abschnitt ZITIEREN in man bash.

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

result=""

foo="FOO"
bar="BAR"

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

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

Ausgabe:

FOO
BAR

FOO
BAR
vern
quelle
1
Warum nicht einfach result+=$foo$'\n'? $(printf %s "$foo")würde die nachgestellten Zeilenumbrüche, $foofalls vorhanden, einschränken .
Stéphane Chazelas
Es gibt keine Erklärung für den Code, sonst sieht es für mich gut aus.
somethingSomething