701 Stimmen

Mehrzeiliger String mit zusätzlichem Leerzeichen (erhaltene Einrückung)

Ich möchte einige vordefinierte Texte in eine Datei schreiben mit folgendem:

text="das ist Zeile eins\n
das ist Zeile zwei\n
das ist Zeile drei"

echo -e $text > dateiname

Ich erwarte etwas wie das hier:

das ist Zeile eins
das ist Zeile zwei
das ist Zeile drei

Aber ich bekomme das hier:

das ist Zeile eins
 das ist Zeile zwei
 das ist Zeile drei

Ich bin sicher, dass kein Leerzeichen nach jedem \n vorhanden ist, aber woher kommt das zusätzliche Leerzeichen?

16voto

Das Folgende ist meine bevorzugte Methode, um einem mehrzeiligen String eine Variable zuzuweisen (ich finde, es sieht gut aus).

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

String1
String2
String3
...
StringN
_______________________________________________________________________________

Die Anzahl der Unterstriche ist in beiden Fällen gleich (hier 80).

10voto

Gabriel Staples Punkte 20228

Schwer zu lesen:

Dieser sieht viel zu bash-ähnlich aus :) (schwer zu lesen) für meinen allgemeinen Geschmack:

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

Besser, einfacher zu lesen:

Lass uns etwas Pythonischeres machen (das ist immer noch bash):

text="this is line one
      this is line two
      this is line three\n"
dedent text
printf "$text"             # auf dem Bildschirm anzeigen
printf "$text" > file.txt  # in eine Datei drucken

Ah...das ist besser. :) Es erinnert mich an die Python textwrap.dedent() Funktion die ich hier verwende.

So sieht die magische dedent Funktion aus:

dedent() {
    local -n reference="$1"
    reference="$(echo "$reference" | sed 's/^[[:space:]]*//')"
}

Beispielausgabe auf dem Bildschirm:

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

Ohne zuerst dedent text aufzurufen, würde die Ausgabe so aussehen:

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

Die Variable text wird per Referenz an dedent übergeben, sodass das, was innerhalb der Funktion geändert wird, die Variable außerhalb der Funktion beeinflusst.

Für weitere Details, Erklärungen und Referenzen siehe meine andere Antwort hier: Äquivalent zu Pythons textwrap dedent in bash

Problem mit deinem ursprünglichen Versuch

OP's Zitat (mit meiner Hervorhebung):

Ich bin sicher, dass es kein Leerzeichen nach jedem \n gibt, aber wie kommt das zusätzliche Leerzeichen zustande?

Dein ursprünglicher Versuch sah so aus:

text="this is line one\n
this is line two\n
this is line three"
echo -e $text

...aber deine Ausgabe hatte ein zusätzliches Leerzeichen vor der 2. und 3. Zeile. Warum?

Durch Deduktion und Experimentieren komme ich zu dem Schluss, dass echo das tatsächliche Zeilenumbruch am Ende der Zeile (das, was du bekommst, wenn du tatsächlich Enter drückst) in ein Leerzeichen umwandelt. Dieses Leerzeichen erscheint daher vor der Zeile direkt nach jedem \n im Text.

Die Lösung ist also, den echten Zeilenumbruch am Ende jeder Zeile zu escapen, indem du einen Backslash \ am Ende jeder Zeile innerhalb der Anführungszeichen deines Strings setzt, so wie hier:

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

echo -e "$text"

Setze kein Leerzeichen vor diese abschließenden Backslashes (so wie hier: text="this is line one\n \) oder das Leerzeichen wird direkt in deine Ausgabe zurückgehen und dasselbe Problem mit dem zusätzlichen Leerzeichen verursachen!

ODER benutze einfach meine Technik mit der dedent Funktion oben, die auch die zusätzliche Funktionalität hat, mit deinem Code einzurücken damit er wirklich hübsch und lesbar aussieht.

7voto

Frank Bryce Punkte 7413

Ich bin hierher gekommen, um nach dieser Antwort zu suchen, aber wollte sie auch an ein anderes Kommando weiterleiten. Die gegebene Antwort ist korrekt, aber wenn jemand es weiterleiten möchte, muss man es vor dem mehrzeiligen String weiterleiten, so wie hier:

echo | tee /tmp/pipetest << EndOfMessage
This is line 1.
This is line 2.
Line 3.
EndOfMessage

Dies ermöglicht es Ihnen, einen mehrzeiligen String zu haben und ihn auch in den Stdin eines nachfolgenden Befehls zu setzen.

3voto

AmanicA Punkte 4283

Gemäß @alphado's Antwort und den anschließenden Kommentaren ist dies, was für mich funktioniert hat und einen 0 Ausgabestatus liefert.

read -r -d '\0' VAR <<- EOM
    Dies ist Zeile 1.
    Dies ist Zeile 2.
    Zeile 3.
\0
EOM
  • <<- um führende Tabs zu ignorieren
  • setze \0 als expliziten "Endmarker"
  • dies substituiert auch Variablen zwischen den EOMs, also verwende \$ um unverändert auszugeben.

(Ich gebe dies als separate Antwort, da es schwer wurde, dies zwischen all den Kommentaren zu entziffern, und ich nicht zu viel an der Originalantwort ändern wollte)

2voto

luk Punkte 37

Es funktioniert, wenn Sie es wie folgt eingeben:

AA='erste Zeile
\nzweite Zeile
\ndritte Zeile'
echo $AA
Ausgabe:
erste Zeile
zweite Zeile
dritte Zeile

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X