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.
0 Stimmen
Verwandt: Echo newline in Bash prints literal \n