Wie vermeidet man eine Bash-Befehlsersetzung, um das Newline-Zeichen zu entfernen?

Um die Ausführung eines Bash-Skripts zu beschleunigen, möchte ich das Ergebnis eines Befehls in einer Variablen mithilfe der 0x0A beibehalten, aber die Befehlssubstitution ersetzt das 0x0A Zeilenumbruchzeichen durch ein Leerzeichen. Beispielsweise:

 a=`df -H` 

oder

 a=$( df -H ) 

Wenn ich weiter $a verarbeiten möchte, werden die Zeilenumbruchzeichen durch ein Leerzeichen ersetzt und alle Zeilen befinden sich jetzt in einer Zeile, was viel schwieriger zu schreiben ist:

 echo $a 

Was wären die einfachen Tricks, um zu verhindern, dass der Zeilenumbruch durch die Befehlsersetzung entfernt wird?

Nicht nachlaufende Zeilenumbrüche werden nicht entfernt

Die Zeilenvorschübe, nach denen Sie suchen, sind dort, Sie sehen sie nur nicht, weil Sie ein echo ohne die Variable zu zitieren.

validation :

 $ 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 darauf hingewiesen, obwohl Zeilenumbrüche in der Ausgabe nicht entfernt werden, werden nachfolgende Zeilenumbrüche mit Befehlsersetzung entfernt. Siehe folgendes Experiment:

 $ 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 Zeilenumbrüche hinzufügt (es sei denn, es wird mit der Option -n aufgerufen), aber es gibt einige Randfälle, in denen mehr als eine nachlaufende Zeilenumbrüche in der Ausgabe eines Programms vorhanden sind sind aus irgendeinem Grund signifikant.

Problemumgehungen

1. Fügen Sie ein Dummy-Zeichen hinzu

In diesem Fall können Sie, wie in @Scrutinizer erwähnt, die folgende Problemumgehung verwenden:

 $ a=$(printf 'test\n\n'; printf x); a=${a%x} $ echo "$a" test $ 

Erläuterung: Zeichen x wird der Ausgabe (mit printf x ) nach den Zeilenumbrüchen hinzugefügt. Da die Zeilenumbrüche nicht mehr folgen, werden sie nicht durch die Befehlsersetzung entfernt. Der nächste Schritt besteht darin, das hinzugefügte x zu entfernen, indem wir den Operator % in ${a%x} . Jetzt haben wir die ursprüngliche Ausgabe mit allen Zeilenumbrüchen!

2. Lesen Sie mit processsubstitution

Anstatt die Ausgabe eines Programms durch Befehlsersetzung einer Variablen zuzuordnen, können wir stattdessen die processsubstitution verwenden , um die Ausgabe des Programms dem integrierten Lesebefehl zuzuführen (Kredit an @ormaaj ). Die processsubstitution behält alle Zeilenumbrüche bei. Das Lesen der Ausgabe in eine Variable ist ein bisschen schwierig, aber Sie können es so machen:

 $ IFS= read -rd '' var < <( printf 'test\n\n' ) $ echo "$var" test $ 

Erläuterung:

  • Wir setzen das interne Feldtrennzeichen für den Lesebefehl mit IFS= auf Null. Andernfalls würde read nicht die gesamte Ausgabe var zuweisen, sondern nur das erste Token.
  • Wir rufen mit den Optionen -rd '' . Das r dient dazu, zu verhindern, dass der Backslash als Sonderzeichen fungiert, und setzt das Delimiter mit d '' auf nothing, so dass read die gesamte Ausgabe liest und nicht nur die erste Zeile.

3. Lesen Sie aus einer Leitung

Anstatt die Ausgabe eines Programms durch eine Befehls- oder processsubstitution einer Variablen zuzuordnen, können wir stattdessen die Ausgabe des Programms an den Lesebefehl übergeben (Kredit an @ ormaaj ). Piping behält auch alle Zeilenumbrüche bei. Beachten Sie jedoch, dass wir diesmal das optionale Verhalten der lastpipe Shell unter Verwendung des shopt Built- shopt festlegen . Dies ist erforderlich, damit der Lesebefehl in der aktuellen Shell-Umgebung ausgeführt wird. Andernfalls wird die Variable in einer Subshell zugewiesen, und auf den Rest des Skripts kann nicht zugegriffen werden.

 $ cat test.sh #!/bin/bash shopt -s lastpipe printf "test\n\n" | IFS= read -rd '' var echo "$var" $ ./test.sh test $ 

Ich habe versucht, meinen Kopf darum zu wickeln, weil ich bash benutzt habe, um das Ergebnis der Ausführung des Interpreters auf einem F # -Skript zu streamen. Nach einigen Versuchen hat sich das Problem getriggers:

 $ 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, dass Sie ein Terminalprogramm ausführen müssen. Hoffe das hilft.