502 Stimmen

Wie kann ich einen Zeilenumbruch in einem String in sh haben?

Diese

STR="Hello\nWorld"
echo $STR

erzeugt als Ausgabe

Hello\nWorld

anstelle von

Hello
World

Was muss ich tun, um einen Zeilenumbruch in einer Zeichenkette zu erhalten?

Anmerkung: Diese Frage bezieht sich nicht auf echo . Ich bin mir bewusst, dass echo -e aber ich suche nach einer Lösung, die die Übergabe einer Zeichenkette (die einen Zeilenumbruch enthält) als Argument an andere Befehle, die nicht über eine ähnliche Option zur Interpretation verfügen \n 's als Zeilenumbrüche.

0 Stimmen

23voto

  1. Die einzige einfache Alternative besteht darin, tatsächlich eine neue Zeile in die Variable einzugeben:

    $ STR='new
    line'
    $ printf '%s' "$STR"
    new
    line

    Ja, das bedeutet Schreiben Enter wo im Code erforderlich.

  2. Es gibt mehrere Äquivalente für ein new line Charakter.

    \n           ### A common way to represent a new line character.
    \012         ### Octal value of a new line character.
    \x0A         ### Hexadecimal value of a new line character.

    Aber all das erfordert eine "Interpretation" durch irgendein Instrument ( POSIX printf ):

    echo -e "new\nline"           ### on POSIX echo, `-e` is not required.
    printf 'new\nline'            ### Understood by POSIX printf.
    printf 'new\012line'          ### Valid in POSIX printf.
    printf 'new\x0Aline'       
    printf '%b' 'new\0012line'    ### Valid in POSIX printf.

    Daher muss das Tool eine Zeichenkette mit einem Zeilenumbruch erstellen:

    $ STR="$(printf 'new\nline')"
    $ printf '%s' "$STR"
    new
    line
  3. In einigen Schalen wird die Sequenz $' ist eine spezielle Shell-Erweiterung. Es ist bekannt, dass sie in ksh93, bash und zsh funktioniert:

    $ STR=$'new\nline'
  4. Natürlich sind auch komplexere Lösungen möglich:

    $ echo '6e65770a6c696e650a' | xxd -p -r
    new
    line

    Oder

    $ echo "new line" | sed 's/ \+/\n/g'
    new
    line

12voto

caot Punkte 2666

Ein $ direkt vor einfachen Anführungszeichen '... \n... ' wie folgt, allerdings funktionieren die doppelten Anführungszeichen nicht.

$ echo $'Hello\nWorld'
Hello
World
$ echo $"Hello\nWorld"
Hello\nWorld

4voto

Jelle Geerts Punkte 743

Haftungsausschluss: Ich habe dies zuerst geschrieben und bin dann über diese Frage gestolpert. Ich dachte, dass diese Lösung noch nicht gepostet wurde, und sah, dass tlwhitec eine ähnliche Antwort gepostet hat. Trotzdem poste ich dies, weil ich hoffe, dass es eine nützliche und gründliche Erklärung ist.

Kurze Antwort:

Dies scheint eine recht portable Lösung zu sein, da sie auf einigen Shells funktioniert (siehe Kommentar).
Auf diese Weise können Sie einen echten Zeilenumbruch in eine Variable einfügen.

Der Vorteil dieser Lösung ist, dass Sie keine Zeilenumbrüche in Ihrem Quellcode verwenden müssen, so dass Sie einrücken können einrücken, wie Sie wollen, und die Lösung funktioniert trotzdem. Das macht sie robust. Außerdem ist sie portabel.

# Robust way to put a real newline in a variable (bash, dash, ksh, zsh; indentation-resistant).
nl="$(printf '\nq')"
nl=${nl%q}

Längere Antwort:

Erläuterung der obigen Lösung:

Der Zeilenumbruch würde normalerweise durch die Befehlssubstitution verloren gehen, aber um das zu verhindern, fügen wir ein 'q' ein und entfernen es anschließend. (Der Grund für die doppelten Anführungszeichen wird weiter unten erklärt).

Wir können beweisen, dass die Variable ein tatsächliches Zeilenumbruchzeichen (0x0A) enthält:

printf '%s' "$nl" | hexdump -C
00000000  0a  |.|
00000001

(Beachten Sie, dass die '%s' benötigt wurde, sonst übersetzt printf ein wörtliches '\n' Zeichenkette in ein tatsächliches 0x0A-Zeichen umzuwandeln, was bedeutet, dass wir nichts beweisen würden).

Natürlich könnte man anstelle der in dieser Antwort vorgeschlagenen Lösung auch diese verwenden (aber...):

nl='
'

... aber das ist weniger robust und kann leicht durch versehentliches Einrücken des Codes beschädigt werden, oder durch das Vergessen, ihn danach wieder auszurücken, was die Verwendung in (eingerückten) Funktionen unpraktisch macht, während die frühere Lösung robust ist.

Und nun zu den Anführungszeichen:
Der Grund für die doppelten Anführungszeichen " um die Befehlssubstitution wie in nl="$(printf '\nq')" ist, dass Sie der Variablenzuweisung dann sogar das Zeichen local Schlüsselwort oder Builtin (z.B. in Funktionen), und es wird immer noch auf allen Shells funktionieren, während sonst die dash Shell hätte insofern Probleme, als dass dash sonst das 'q' verlieren würde und Sie am Ende eine leere 'nl'-Variable hätten (wiederum aufgrund der Befehlssubstitution).
Dieses Problem lässt sich anhand eines anderen Beispiels besser veranschaulichen:

dash_trouble_example() {
    e=$(echo hello world) # Not using 'local'.
    echo "$e" # Fine. Outputs 'hello world' in all shells.

    local e=$(echo hello world) # But now, when using 'local' without double quotes ...:
    echo "$e" # ... oops, outputs just 'hello' in dash,
              # ... but 'hello world' in bash and zsh.

    local f="$(echo hello world)" # Finally, using 'local' and surrounding with double quotes.
    echo "$f" # Solved. Outputs 'hello world' in dash, zsh, and bash.

    # So back to our newline example, if we want to use 'local', we need
    # double quotes to surround the command substitution:
    # (If we didn't use double quotes here, then in dash the 'nl' variable
    # would be empty.)
    local nl="$(printf '\nq')"
    nl=${nl%q}
}

Praktisches Beispiel für die obige Lösung:

# Parsing lines in a for loop by setting IFS to a real newline character:

nl="$(printf '\nq')"
nl=${nl%q}

IFS=$nl

for i in $(printf '%b' 'this is line 1\nthis is line 2'); do
    echo "i=$i"
done

# Desired output:
# i=this is line 1
# i=this is line 2

# Exercise:
# Try running this example without the IFS=$nl assignment, and predict the outcome.

3voto

Jason Punkte 2502

Ich bin kein Bash-Experte, aber bei mir hat das funktioniert:

STR1="Hello"
STR2="World"
NEWSTR=$(cat << EOF
$STR1

$STR2
EOF
)
echo "$NEWSTR"

Ich fand es einfacher, die Texte zu formatieren.

2 Stimmen

Der gute alte heredoc . Und wahrscheinlich ist es auch POSIX-konform!

1 Stimmen

Die Anführungszeichen um $NEWSTR en echo "$NEWSTR" sind hier wichtig

2voto

Karthik Suresh Punkte 19

Das ist nicht ideal, aber ich hatte eine Menge Code geschrieben und Zeichenketten auf eine ähnliche Weise definiert wie in der Frage. Die akzeptierte Lösung verlangte von mir, einen großen Teil des Codes zu überarbeiten, also habe ich stattdessen jeden \n con "$'\n'" und das hat bei mir funktioniert.

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