Nicht nachfolgende Zeilenumbrüche werden nicht entfernt
Die gesuchten Zeilenumbrüche sind da, Sie sehen sie einfach nicht, weil Sie sie verwenden, echo
ohne die Variable in Anführungszeichen zu setzen .
Validierung :
$ a=$( df -H )
$ echo $a
Filesystem Size Used Avail Use% Mounted on /dev/sda3 276G 50G 213G 19% / udev 2.1G 4.1k 2.1G 1% /dev tmpfs 832M 820k 832M 1% /run none 5.3M 0 5.3M 0% /run/lock none 2.1G 320k 2.1G 1% /run/shm
$ echo "$a"
Filesystem Size Used Avail Use% Mounted on
/dev/sda3 276G 50G 213G 19% /
udev 2.1G 4.1k 2.1G 1% /dev
tmpfs 832M 820k 832M 1% /run
none 5.3M 0 5.3M 0% /run/lock
none 2.1G 320k 2.1G 1% /run/shm
$
Nachgestellte Zeilenumbrüche werden entfernt
Wie @ user4815162342 richtig hervorhob , werden nachfolgende Zeilenumbrüche durch Befehlsersetzung entfernt, obwohl Zeilenumbrüche in der Ausgabe nicht entfernt werden. Siehe Experiment unten:
$ a=$'test\n\n'
$ echo "$a"
test
$ b=$(echo "$a")
$ echo "$b"
test
$
In den meisten Fällen spielt dies keine Rolle, da echo
die entfernte neue Zeile hinzugefügt wird (es sei denn, sie wird mit der -n
Option aufgerufen ). In einigen Randfällen gibt es jedoch mehr als eine nachfolgende Zeile in der Ausgabe eines Programms, und sie sind für diese von Bedeutung irgendein Grund.
Problemumgehungen
1. Fügen Sie ein Dummy-Zeichen hinzu
In diesem Fall können Sie, wie bei @Scrutinizer erwähnt, die folgende Problemumgehung verwenden:
$ a=$(printf 'test\n\n'; printf x); a=${a%x}
$ echo "$a"
test
$
Erläuterung: Nach den Zeilenumbrüchen wirdx
der Ausgabe (usingprintf x
) einZeichenhinzugefügt. Da die Zeilenumbrüche nicht mehr nachlaufen , werden sie durch die Befehlsersetzung nicht entfernt. Der nächste Schritt besteht darin, dasx
hinzugefügte Element mithilfe des%
Operators inzu entfernen${a%x}
. Jetzt haben wir die Originalausgabe mit allen Zeilenumbrüchen !!!
2. Lesen Sie mit Prozessersetzung
Anstatt die Befehlssubstitution zu verwenden, um die Ausgabe eines Programms einer Variablen zuzuweisen, können wir stattdessen die Prozessersetzung verwenden , um die Ausgabe des Programms dem read
integrierten Befehl zuzuführen (Gutschrift an @ormaaj ). Durch die Prozessersetzung bleiben alle Zeilenumbrüche erhalten. Das Lesen der Ausgabe in eine Variable ist etwas schwierig, aber Sie können dies folgendermaßen tun:
$ IFS= read -rd '' var < <( printf 'test\n\n' )
$ echo "$var"
test
$
Erläuterung:
- Wir setzen das interne Feldtrennzeichen für den Lesebefehl auf null mit
IFS=
. Andernfalls read
würde nicht die gesamte Ausgabe zugewiesen var
, sondern nur das erste Token.
- Wir rufen
read
mit Optionen auf -rd ''
. Das r
ist zum Verhindern des umgekehrten Schrägstrich als Sonderzeichen zu handeln und mit d ''
den Begrenzer zu nichts festgelegt, so dass Lesen Sie die gesamte Ausgabe liest, statt nur die erste Zeile.
3. Lesen Sie aus einem Rohr
Anstatt eine Befehls- oder Prozessersetzung zu verwenden, um die Ausgabe eines Programms einer Variablen zuzuweisen, können wir stattdessen die Ausgabe des Programms an den read
Befehl weiterleiten (Gutschrift an @ormaaj ). Durch die Rohrleitungen bleiben auch alle Zeilenumbrüche erhalten. Beachten Sie jedoch, dass wir diesmal das lastpipe
optionale Verhalten der Shell mithilfe der integrierten Funktion shopt
festlegen . Dies ist erforderlich, damit der read
Befehl in der aktuellen Shell-Umgebung ausgeführt wird. Andernfalls wird die Variable in einer Subshell zugewiesen und kann vom Rest des Skripts nicht aufgerufen werden.
$ cat test.sh
shopt -s lastpipe
printf "test\n\n" | IFS= read -rd '' var
echo "$var"
$ ./test.sh
test
$
a=$(printf 'test\n\n'; printf x); echo "${a%x}"
read
nicht standardmäßige Optionen für die Zuweisung zu verwenden.shopt -s lastpipe; printf %s "$myData" | IFS= read -rd '' var
. Bash'sprintf -v
ist auch in ähnlichen Situationen nützlich.lastpipe
(obwohl ich sie normalerweiselastpipe
sowieso verwende). Der Grund, warum Sie dies bemerken, liegt in der Jobkontrolle. Interaktive Shells habenset -m
die Möglichkeit, Pipelines in separaten Prozessgruppen auszuführen, was eine Unter-Shell für das letzte Element erforderlich macht. Da die Jobsteuerung nicht für Kinder einer Subshell gilt, ist das Einpacken alles eine Problemumgehung(...)
(was ich sowieso fast immer mache, wenn ich interaktiv teste).read
Wird mit Null beendet, wenn EOF erreicht wird. Dies führt dazu, dass die Methoden 2 und 3 mit einem Wert ungleich Null beendet werden, wodurch der Beendigungsstatus des Hauptbefehls maskiert wird. In Methode 1main_cmd ; printf x
überschreibt die Verwendung auch den Exit-Code der Hauptbefehle und stört die Fehlerbehandlung. Versuchen Sie esmain_cmd && printf x
stattdessen (wenn nachfolgende Zeilen nur beim Beenden des Erfolgs wichtig sind) odermain_cmd ; ec=$?; printf x; exit $ec
um nachgestellte Leerzeichen sowohl in Erfolgs- als auch in Fehlerfällen beizubehalten.Ich habe versucht, meinen Kopf darum zu wickeln, weil ich Bash verwendet habe, um das Ergebnis des Ausführens des Interpreters in einem F # -Skript zu streamen. Nach einigem Ausprobieren stellte sich heraus, dass dies das Problem löste:
$ cat fsi.ch #!/bin/bash echo "$(fsharpi --quiet --exec --nologo $1)" $ fsi.ch messages.fsx Welcome to my program. Choose from the menu: new | show | remove
Vorausgesetzt natürlich, Sie müssen ein Terminalprogramm ausführen. Hoffe das hilft.
quelle
Ein weiterer "netter Trick" ist die Verwendung des Wagenrücklaufzeichens, das verhindert, dass die neue Zeile entfernt wird, aber nichts zur Ausgabe hinzufügt:
$ my_func_1 () { > echo "This newline is squashed" > } $ my_func_2 () { > echo "This newline is not squashed" > echo -n $'\r' > } $ echo -n "$(my_func_1)" && echo -n "$(my_func_2)" && echo done This newline is squashedThis newline is not squashed done $
Aber Käufer aufgepasst: Wie in den Kommentaren erwähnt, kann dies gut für Ausgaben funktionieren, die einfach an das Terminal gesendet werden. Wenn Sie dies jedoch an einen anderen Prozess weitergeben, können Sie es verwirren, da es wahrscheinlich nicht mit dem seltsamen Beenden rechnen wird
'\r'
.quelle
echo -n "$(my_func_2)" | cat -A
ansehen, werden Sie feststellen, dass die$'\r'
Ausgabe in der Ausgabe erhalten bleibt. Dies kann zu Problemen führen, wenn der Empfängerprozess dies nicht erwartet.