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?

1034voto

alphadog Punkte 10563

Wiedereingabe klingt dies für diesen Zweck bequemer. Es wird verwendet, um mehrere Befehle an ein Befehlsinterpreterprogramm wie ex oder cat zu senden

cat << EndOfMessage
Dies ist Zeile 1.
Dies ist Zeile 2.
Zeile 3.
EndOfMessage

Der String nach << gibt an, wo gestoppt werden soll.

Um diese Zeilen in eine Datei zu senden, verwenden Sie:

cat > $FILE <<- EOM
Zeile 1.
Zeile 2.
EOM

Sie könnten diese Zeilen auch in einer Variablen speichern:

read -r -d '' VAR << EOM
Dies ist Zeile 1.
Dies ist Zeile 2.
Zeile 3.
EOM

Dies speichert die Zeilen in der Variablen mit dem Namen VAR.

Beim Drucken sollten Sie sich an die Anführungszeichen um die Variable erinnern, sonst sehen Sie die Zeilenumbruchszeichen nicht.

echo "$VAR"

Noch besser ist die Verwendung von Einrückungen, um sie in Ihrem Code besser sichtbar zu machen. Diesmal fügen Sie nach << einfach ein - hinzu, um zu verhindern, dass die Tabulatoren im Text erscheinen.

read -r -d '' VAR <<- EOM
    Dies ist Zeile 1.
    Dies ist Zeile 2.
    Zeile 3.
EOM

Aber dann müssen Sie Tabulatoren, keine Leerzeichen, für die Einrückung in Ihrem Code verwenden.

372voto

Andrew Miner Punkte 4681

Wenn Sie versuchen, den String in eine Variable zu bekommen, gibt es eine weitere einfache Möglichkeit, wie folgt:

VERWENDUNG=$(cat << -END
    Dies ist Zeile eins.
    Dies ist Zeile zwei.
    Dies ist Zeile drei.
END

)

Wenn Sie Ihren String mit Tabs einrücken (d.h. '\t'), wird die Einrückung entfernt. Wenn Sie mit Leerzeichen einrücken, bleibt die Einrückung erhalten.

HINWEISE:

  • Es ist bedeutend, dass die letzte schließende Klammer in einer anderen Zeile steht. Der Text END muss in einer eigenen Zeile stehen.
  • Wenn Sie diese Variable verwenden, um nicht lesbare Zeichen (\t, \n) zu erhalten, müssen Sie sie in Anführungszeichen setzen. Also verwenden Sie echo "$VERWENDUNG" (nicht: echo $VERWENDUNG)

129voto

Josh Jolly Punkte 10808

echo fügt Leerzeichen zwischen den übergebenen Argumenten hinzu. $text unterliegt der Variablenexpansion und der Wortaufspaltung, sodass Ihr echo-Befehl äquivalent zu folgendem ist:

echo -e "this" "is" "line" "one\n" "this" "is" "line" "two\n"  ...

Sie können sehen, dass ein Leerzeichen vor "this" hinzugefügt wird. Sie können entweder die Zeilenumbruchzeichen entfernen und $text in Anführungszeichen setzen, um die Zeilenumbrüche beizubehalten:

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

echo "$text" > filename

Oder Sie könnten printf verwenden, das robuster und portabler ist als echo:

printf "%s\n" "this is line one" "this is line two" "this is line three" > filename

In bash, das die Klammersetzung unterstützt, könnten Sie sogar Folgendes tun:

printf "%s\n" "this is line "{one,two,three} > filename

72voto

Chris Maes Punkte 30364

In einem Bash-Skript funktioniert folgendes:

#!/bin/sh

text="this is line one\nthis is line two\nthis is line three"
echo -e $text > filename

alternativ:

text="this is line one
this is line two
this is line three"
echo "$text" > filename

cat filename gibt:

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

49voto

Mateusz Piotrowski Punkte 6778

Ich habe mehr Lösungen gefunden, seitdem ich wollte, dass jede Zeile ordnungsgemäß eingerückt ist:

  1. Sie können echo verwenden:

    echo    "this is line one"   \
        "\n""this is line two"   \
        "\n""this is line three" \
        > filename

    Es funktioniert nicht, wenn Sie "\n" direkt vor \ am Ende einer Zeile platzieren.

  2. Alternativ können Sie printf für bessere Portabilität verwenden (ich hatte zufällig viele Probleme mit echo):

    printf '%s\n' \
        "this is line one"   \
        "this is line two"   \
        "this is line three" \
        > filename
  3. Noch eine weitere Lösung könnte sein:

    text=''
    text="${text}this is line one\n"
    text="${text}this is line two\n"
    text="${text}this is line three\n"
    printf "%b" "$text" > filename

    oder

    text=''
    text+="this is line one\n"
    text+="this is line two\n"
    text+="this is line three\n"
    printf "%b" "$text" > filename
  4. Eine weitere Lösung wird durch die Kombination von printf und sed erzielt.

    if something
    then
        printf '%s' '
        this is line one
        this is line two
        this is line three
        ' | sed '1d;$d;s/^    //g'
    fi

    Es ist nicht einfach, Code, der so formatiert ist, umzugestalten, da Sie das Einrückungsniveau im Code fest codieren.

  5. Es ist möglich, eine Hilfsfunktion und einige Tricks mit Variablensubstitution zu verwenden:

    unset text
    _() { text="${text}${text+
    }${*}"; }
    # Das ist eine leere Zeile, die die Begründung hinter
    # der Verwendung von "+" anstelle von ":+" in der Variablensubstitution
    # oben demonstriert.
    _ ""
    _ "this is line one"
    _ "this is line two"
    _ "this is line three"
    unset -f _
    printf '%s' "$text"

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