Zitierte oder nicht zitierte String-Erweiterung

11
  1. for i in $(xrandr); do echo "$i" ; done
  2. for i in "$(xrandr)"; do echo "$i"; done
  3. for i in "$(xrandr)"; do echo $i; done

Ich verstehe, warum 1 von 2 abweicht. Aber warum gibt 3 eine andere Ausgabe von 2? Bitte erläutern Sie auch die Ausgabe. Wie funktionieren Zitate in Zeilenumbrüchen?

ManuelSchneid3r
quelle

Antworten:

19

Eine nicht zitierte Variable (wie in $var) oder Befehlssubstitution (wie in $(cmd)oder `cmd`) ist der Operator split + glob in Bourne-ähnlichen Shells.

Das heißt, ihr Inhalt wird gemäß dem aktuellen Wert der $IFSSondervariablen aufgeteilt (die standardmäßig die Zeichen für Leerzeichen, Tabulatoren und Zeilenumbrüche enthält).

Und dann unterliegt jedes Wort, das sich aus dieser Aufteilung ergibt, der Dateinamengenerierung (auch als Globbing oder Dateinamenerweiterung bezeichnet ), dh sie werden als Muster betrachtet und auf die Liste der Dateien erweitert, die diesem Muster entsprechen.

Also for i in $(xrandr), die $(xrandr), weil sie nicht in Anführungszeichen sind, wird aufgeteilt auf Sequenzen von Raum, Tab und Zeilenumbrüchen. Und jedes Wort, das sich aus dieser Aufteilung ergibt, wird auf übereinstimmende Dateinamen überprüft (oder so belassen, als ob sie keiner Datei entsprechen) und foralle durchlaufen.

In for i in "$(xrandr)"wird der Operator split + glob nicht verwendet, da die Befehlssubstitution in Anführungszeichen gesetzt wird. Daher gibt es in der Schleife einen Durchgang für einen Wert: die Ausgabe von xrandr(ohne die nachgestellten Zeilenumbruchzeichen, die Substitutionsstreifen befehlen ).

Jedoch in echo $i, $iwieder unquoted, also wieder der Inhalt der $igeteilt ist und je nach Dateinamen Generation und diese werden als getrennte Argumente an den übergebenen echoBefehl (und echogibt seine Argumente durch Leerzeichen getrennt sind).

So gelernt Lektion:

  • Wenn Sie keine Wortteilung oder Dateinamengenerierung wünschen , geben Sie immer Variablenerweiterungen und Befehlsersetzungen an
  • Wenn Sie eine Wortaufteilung oder Dateinamengenerierung wünschen , lassen Sie sie nicht in Anführungszeichen, sondern stellen Sie sie $IFSentsprechend ein und / oder aktivieren oder deaktivieren Sie die Dateinamengenerierung, falls erforderlich ( set -f, set +f).

Wenn Sie in Ihrem obigen Beispiel die leere, getrennte Liste von Wörtern in der Ausgabe von xrandrdurchlaufen möchten , müssen Sie normalerweise Folgendes tun:

  • verlassen $IFSauf seinem Standardwert (oder löschen) zu Split auf Zuschnitte
  • Verwenden Sie set -fdiese Option, um die Dateinamengenerierung zu deaktivieren, es sei denn, Sie sind sicher, dass xrandrniemals ein *oder ?mehrere [Zeichen ausgegeben werden (dies sind Platzhalter, die in Dateinamengenerierungsmustern verwendet werden).

Verwenden Sie dann nur den Operator split + glob (lassen Sie die Befehlssubstitution oder die Variablenerweiterung nur ohne Anführungszeichen) im inTeil der forSchleife:

set -f; unset -v IFS
for i in $(xrandr); do whatever with "$i"; done

Wenn Sie die (nicht leeren) Zeilen der xrandrAusgabe $IFSdurchlaufen möchten , müssen Sie das Zeilenumbruchzeichen festlegen:

IFS='
'
Stéphane Chazelas
quelle
4

Eine zitierte Newline ist eine Newline. echo "$1"Gibt dem Echo also ein einzelnes Befehlszeilenargument, das dann die Zeilenumbrüche direkt druckt.

Ein nicht zitierter Zeilenumbruch ist Leerzeichen. Es echo $1gibt also viele Befehlszeilenargumente für echo, die nacheinander durch Leerzeichen getrennt gedruckt werden.

Rici
quelle
Ein nicht zitierter Zeilenumbruch ist, dass Leerzeichen eine etwas zu große Abkürzung sind, um als Erklärung für das Verhalten hier IMO wirklich nützlich zu sein.
Stéphane Chazelas