Mehrzeiliger String mit zusätzlichem Leerzeichen (erhaltener Einzug)

409

Ich möchte einige vordefinierte Texte in eine Datei schreiben, die Folgendes enthält:

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

echo -e $text > filename

Ich erwarte so etwas:

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

Aber hab das:

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

Ich bin mir sicher, dass nach jedem kein Platz mehr vorhanden ist \n, aber wie kommt der zusätzliche Platz heraus?

Cizixs
quelle
2
Ich bin mir nicht sicher, aber wie wäre es, wenn Sie nur text="this is line one\nthis is line two\nthis is line three"dieselbe Zeile eingeben würden? (ohne Eingabe)
Yohanes Khosiawan 许先汉
4
Entfernen Sie die \nin jeder Zeile, Sie haben bereits die neue Zeile gedrückt, um zur neuen Zeile zu wechseln
Mark Setchell
Sie haben bereits angegeben \n. Warum setzen Sie die nächste Zeile in eine neue Zeile? Einfachtext="this is line one\nthis is line two\nthis is line three"
Jayesh Bhoi
1
Wenn Sie das \nam Ende jeder Zeile entfernen , werden alle Ausgaben zusammen in einer einzelnen Zeile ausgeführt.
Jonathan Hartley
18
Aha: Es "$text"ist entscheidend, doppelte Anführungszeichen in die Echolinie zu setzen. Ohne sie funktioniert keine der Zeilenumbrüche (sowohl wörtlich als auch '\ n'). Mit ihnen tun sie alle.
Jonathan Hartley

Antworten:

661

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

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

Die Zeichenfolge danach <<gibt an, wo angehalten werden soll.

Verwenden Sie zum Senden dieser Zeilen an eine Datei:

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

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

read -r -d '' VAR << EOM
This is line 1.
This is line 2.
Line 3.
EOM

Dadurch werden die Zeilen in der benannten Variablen gespeichert VAR.

Beachten Sie beim Drucken die Anführungszeichen um die Variable, da sonst die Zeilenumbruchzeichen nicht angezeigt werden.

echo "$VAR"

Noch besser ist, dass Sie Einrückungen verwenden können, um sie in Ihrem Code besser hervorzuheben. Fügen Sie diesmal einfach ein -Nachher hinzu <<, um zu verhindern, dass die Registerkarten angezeigt werden.

read -r -d '' VAR <<- EOM
    This is line 1.
    This is line 2.
    Line 3.
EOM

Dann müssen Sie jedoch Tabulatoren und keine Leerzeichen zum Einrücken in Ihren Code verwenden.

Neues Kind
quelle
38
Warum haben Sie << - anstelle von << in der ersten Zeile des 2. und 5. Codeblocks? macht - etwas Besonderes?
Lohfu
35
@ sup3rman '-' Ignoriert führende Registerkarten. Siehe stackoverflow.com/questions/2500436/…
kervin
7
Wie kann ich das Lesen mit dem Status 0 beenden? Es scheint, dass es das Zeilenende nicht finden kann (da es -d '' ist) und mit 1 beendet wird, was nicht hilft, wenn Sie sich im Skript befinden.
Mischa Slyusarev
6
@MishaSlyusarev benutze -d '\ 0' und füge am Ende deiner letzten Zeile eine \ 0 hinzu
Lars Schneider
11
Verwendung der -d Option in read -r -d '' VARIABLE <<- EOMhat bei mir nicht funktioniert.
dron22
186

Wenn Sie versuchen, den String in eine Variable zu bringen, ist ein anderer einfacher Weg wie folgt:

USAGE=$(cat <<-END
    This is line one.
    This is line two.
    This is line three.
END
)

Wenn Sie Ihre Zeichenfolge mit Tabulatoren (dh '\ t') einrücken, wird die Einrückung entfernt. Wenn Sie mit Leerzeichen einrücken, bleibt die Einrückung in.

HINWEIS: Es ist wichtig, dass sich die letzte schließende Klammer in einer anderen Zeile befindet. Der ENDText muss in einer eigenen Zeile erscheinen.

Andrew Miner
quelle
1
Ist das wichtig? Funktioniert auf meinem Mac mit )derselben Zeile. Ich denke, das liegt daran, dass das, was dazwischen liegt $(und )in seinem eigenen Universum ausgeführt wird, und der eigentliche Befehl ')' sowieso nicht sieht. Ich frage mich, ob es auch für andere funktioniert.
DJ
Es ist möglich, dass verschiedene Muscheln die Dinge unterschiedlich interpretieren. In der Bash-Dokumentation scheint es nicht so oder so etwas zu sagen, aber alle Beispiele haben es in einer eigenen Zeile.
Andrew Miner
Es macht Spaß, ich habe festgestellt, dass Sie eine Antwort erhalten, wenn Sie versuchen, den Wert auch für die Variable USAGE festzulegen. Ihre Antwort stimmt also genau überein. :)
Bunyk
1
@deej Aus der POSIX-Spezifikation : Das Here-Dokument… wird fortgesetzt, bis eine Zeile nur das Trennzeichen und eine <neue> Zeile enthält
Fornost
1
@Fornost Es widerspricht nicht, was ich gesagt habe
DJ
84

echoFügt Leerzeichen zwischen den übergebenen Argumenten ein. $textunterliegt einer variablen Erweiterung und Wortaufteilung, daher entspricht Ihr echoBefehl:

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

Sie können sehen, dass vor "this" ein Leerzeichen hinzugefügt wird. Sie können entweder die Zeilenumbruchzeichen entfernen und zitieren $text, 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 verwenden printf, das robuster und tragbarer ist als echo:

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

In bash, das die Erweiterung der Zahnspange unterstützt, können Sie sogar Folgendes tun:

printf "%s\n" "this is line "{one,two,three} > filename
Josh Jolly
quelle
1
Danke, dass du erklärt hast, warum Mod zusätzlichen Platz sieht, wenn er den Befehl "echo" verwendet. Diese Antwort funktioniert auch gut, wenn sie im Bash-Skript verwendet wird (im Gegensatz zur interaktiven Shell-Sitzung). Fühlen Sie sich wie dies ist die wahre Antwort und sollte eine akzeptierte Antwort sein.
onelaview
1
Dies sollte als Antwort akzeptiert werden. Alle anderen Antworten lieferten unzählige interessante andere Möglichkeiten, um den Schmerz von OP zu lösen, aber technisch war die Frage "Wie kommt der zusätzliche Platz heraus" und niemand ging darauf ein :-) !!! Danke, Josh, dass du -1 Rätsel gemacht hast!
Dmitry Shevkoplyas
45

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

Alternative:

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

Katze Dateiname gibt:

this is line one
this is line two
this is line three
Chris Maes
quelle
Es scheint, dass der alternative Trick bei Shell-Skripten funktioniert, bei Bash jedoch nicht.
Macindows
3
@ Macindows Ich habe anscheinend die -eOption für vergessen echo. Bitte versuche es erneut.
Chris Maes
41

Ich habe mehr Lösungen gefunden, da ich wollte, dass jede Zeile richtig eingerückt wird:

  1. Sie können verwenden echo:

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

    Es funktioniert nicht, wenn Sie "\n"kurz zuvor \am Ende einer Zeile setzen.

  2. Alternativ können Sie printffür eine 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. 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 andere Lösung wird durch Mischen von printfund erreicht sed.

    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, so formatierten Code umzugestalten, wenn Sie die Einrückungsstufe in den Code fest codieren.

  5. Es ist möglich, eine Hilfsfunktion und einige Tricks zur variablen Substitution zu verwenden:

    unset text
    _() { text="${text}${text+
    }${*}"; }
    # That's an empty line which demonstrates the reasoning behind 
    # the usage of "+" instead of ":+" in the variable substitution 
    # above.
    _ ""
    _ "this is line one"
    _ "this is line two"
    _ "this is line three"
    unset -f _
    printf '%s' "$text"
Mateusz Piotrowski
quelle
3b ist meine bevorzugte Lösung, wenn Codeeinrückung und Zeichenfolgeneinrückung unabhängig voneinander beibehalten werden sollen, zumindest wenn ich 2 nicht für die Variablenzuweisung verwenden kann und besser lesbar ist als 3a. Wenn es mich nicht interessiert, halte ich einfach die angegebene Zeichenfolge über die verschiedenen Zeilen offen.
Pysis
Sehr schöne Antwort vor allem 3b
Sumit Trehan
"Es funktioniert nicht, wenn Sie" \ n "kurz vor \ am Ende einer Zeile setzen." - ist ein guter Tipp bei der Verwendung von Echo.
Noam Manos
6

Das Folgende ist meine bevorzugte Methode, um einer Variablen eine mehrzeilige Zeichenfolge zuzuweisen (ich finde, sie sieht gut aus).

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

String1
String2
String3
...
StringN
_______________________________________________________________________________

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

Frank-Rene Schäfer
quelle
0

Nur um eine einfache einzeilige Verkettung zu erwähnen, da sie manchmal nützlich sein kann.

# for bash

v=" guga "$'\n'"   puga "

# Just for an example.
v2="bar "$'\n'"   foo "$'\n'"$v"

# Let's simplify the previous version of $v2.
n=$'\n'
v3="bar ${n}   foo ${n}$v"

echo "$v3" 

Sie werden so etwas bekommen

Bar 
   foo 
 Guga 
   Puga 

Alle führenden und endenden Leerzeichen bleiben für erhalten

echo "$v3" > filename
it3xl
quelle
0

Es gibt viele Möglichkeiten, dies zu tun. Für mich funktioniert es gut , die eingerückte Saite in sed zu leiten.

printf_strip_indent() {
   printf "%s" "$1" | sed "s/^\s*//g" 
}

printf_strip_indent "this is line one
this is line two
this is line three" > "file.txt"

Diese Antwort basierte auf der Antwort von Mateusz Piotrowski , wurde aber etwas verfeinert.

Beni Trainor
quelle
-1

es wird funktionieren, wenn Sie es wie folgt setzen:

AA='first line
\nsecond line 
\nthird line'
echo $AA
output:
first line
second line
third line
luk
quelle