POSIX-Shell: Verliert "$" seine besondere Bedeutung, wenn es sich um das letzte Zeichen in einem Wort handelt?

17

Auf Asche, Dash und Bash, wenn ich renne

$ echo ab$

es kehrt zurück

ab$

Wird dieses Verhalten von POSIX spezifiziert oder ist es nur eine übliche Konvention in POSIX-kompatiblen Shells? Auf der Seite POSIX Shell Command Language konnte nichts gefunden werden, das dieses Verhalten erwähnt.

Harold Fischer
quelle
4
Die bessere Frage lautet : „Does $ gewinnt eine besondere Bedeutung , wenn es das letzte Zeichen in einem Wort?“ Es ist keine einzige spezielle Bedeutung zugeordnet $; Es wird verwendet, um mehrere, aber unterschiedliche Erweiterungen wie Parametererweiterungen ${...}, Befehlssubstitutionen $(...)und arithmetische Ausdrücke einzuführen $((...)). Einige Shells führen zusätzliche Kontexte ein, z. B. kshdie Befehlsersetzungsvariante x=${ echo foo; echo bar;}(die sich vom Standard $(...)dadurch unterscheidet, dass die Befehle nicht in einer Subshell ausgeführt werden).
Chepner
@chepner Möchtest du die Meinungsverschiedenheiten zwischen Issac und Michael Homer abwägen? Ihre Antworten widersprechen sich ausdrücklich
Harold Fischer
1
Ich stimme Michael Homers Interpretation zu. Die Shell macht sich erst nach Abschluss des Parsings Gedanken über Erweiterungen. In einem einzelnen Wort ab$folgt also kein Zeichen $, unabhängig davon, ob ein Nullzeichen in der ursprünglichen Eingabezeichenfolge oder ein Leerzeichen in einer Groß- / Kleinschreibung "gefolgt" wurde mögen echo ab$ foo; Das ursprüngliche Leerzeichen ohne Anführungszeichen wurde erkannt und nach dem Parsen verworfen.
Chepner

Antworten:

10

$nicht eine besondere Bedeutung für sich allein hat (Versuch echo $), nur wenn sie mit anderem Charakter kombiniert , nachdem sie und eine Erweiterung bilden, zum Beispiel $var(oder ${var}) $(util), $((1+2)).

Das $bekommt seine "besondere" Bedeutung als Definition einer Erweiterung im POSIX-Standard unter dem Abschnitt Tokenerkennung :

Wenn das aktuelle Zeichen ein unquoted ist $oder `wird die Schale , die den Beginn eines jeden Kandidaten für die Parameter, Kommando - Substitutionen, oder arithmetische Expansion von ihren Einführungs unquoted Zeichenfolge identifizieren: $oder ${, $(oder `und $((, respectively. Die Shell muss genügend Eingaben lesen, um das Ende der zu erweiternden Einheit zu bestimmen ( wie in den angegebenen Abschnitten erläutert)). Wenn bei der Verarbeitung der Zeichen Erweiterungen oder Anführungszeichen in der Ersetzung verschachtelt sind, verarbeitet die Shell diese rekursiv in der für das gefundene Konstrukt angegebenen Weise. Die Zeichen, die vom Beginn der Ersetzung bis zu ihrem Ende gefunden wurden und eine Rekursion ermöglichen, die zum Erkennen eingebetteter Konstrukte erforderlich ist, werden unverändert in das Ergebnistoken aufgenommen, einschließlich eingebetteter oder einschließender Ersetzungsoperatoren oder Anführungszeichen. Der Token wird nicht durch das Ende der Ersetzung begrenzt.

Wenn sich $also keine Erweiterung bildet, werden andere Parsing-Regeln wirksam:

Wenn das vorherige Zeichen Teil eines Wortes war, wird das aktuelle Zeichen an dieses Wort angehängt.

Das deckt deine ab$Saite ab.

Im Falle eines Einzelnen $(das "neue Wort" wäre das $für sich):

Das aktuelle Zeichen wird als Beginn eines neuen Wortes verwendet.

Die Bedeutung des generierten Wortes, das eine $nicht standardmäßige Erweiterung enthält , wird von POSIX explizit als nicht angegeben definiert.

Beachten Sie auch, dass dies $das letzte Zeichen in $$ist, dies jedoch auch die Variable ist, die die PID der aktuellen Shell enthält. In bash, !$kann eine Verlaufserweiterung aufrufen (das letzte Argument des vorherigen Befehls). Nein, im Allgemeinen $ist es nicht ohne Bedeutung am Ende eines nicht zitierten Wortes, aber am Ende eines Wortes bedeutet es zumindest keine Standarderweiterung.

Kusalananda
quelle
7

Abhängig von der genauen Situation ist dies entweder explizit nicht spezifiziert (so dass Implementierungen möglicherweise so funktionieren, wie sie es wollen) oder es muss geschehen, wie Sie es beobachtet haben. In Ihrem genauen Szenario echo ab$, beauftragt POSIX die Ausgabe „ab $“ , dass Sie beobachtet und es ist nicht nicht näher bezeichnet . Eine kurze Zusammenfassung aller verschiedenen Fälle ist am Ende.

Es gibt zwei Elemente: erst das Tokenisieren in Wörter und dann die Interpretation dieser Wörter.


Tokenisierung

Die POSIX-Tokenisierung erfordert, dass a $nicht der Beginn einer gültigen Parametererweiterung , einer Befehlssubstitution oder einer arithmetischen Substitution ist , um als wörtlicher Teil des zu erstellenden WORDTokens betrachtet zu werden. Dies liegt daran, dass Regel 5 ("Wenn das aktuelle Zeichen nicht in Anführungszeichen $oder steht `, identifiziert die Shell den Beginn von Kandidaten für Parametererweiterung, Befehlssubstitution oder arithmetische Erweiterung anhand ihrer einleitenden nicht in Anführungszeichen stehenden Zeichenfolgen: $oder ${, $(oder `, und $((bzw.") ) entfällt, da dort keine dieser Erweiterungen realisierbar ist. Für die Parametererweiterung muss ein gültiger Name angegeben werden, und ein leerer Name ist ungültig.

Da diese Regel nicht galt, folgen wir weiter, bis wir eine finden, die dies tut. Die beiden Kandidaten sind # 8 ("Wenn das vorherige Zeichen Teil eines Wortes war, wird das aktuelle Zeichen an dieses Wort angehängt.") Und # 10 ("Das aktuelle Zeichen wird als Anfang eines neuen Wortes verwendet."). , die gelten fürecho a$ und echo $verbunden.

Es gibt auch einen dritten Fall des Formulars echo a$+b der durch denselben Riss fällt, da +es sich nicht um den Namen eines speziellen Parameters handelt. Auf diesen werden wir später zurückkommen, da er verschiedene Teile der Regeln auslöst.

Die Spezifikation verlangt daher, dass die $ Wort syntaktisch als Teil des Wortes betrachtet und später weiterverarbeitet werden kann.


Worterweiterung

Nachdem die Eingabe auf diese Weise analysiert wurde, werden mit dem $im Wort enthaltenen Wort Worterweiterungen auf jedes der gelesenen Wörter angewendet. Jedes Wort wird einzeln verarbeitet .

Es wird angegeben, dass :

Wenn auf ein '$' ohne Anführungszeichen ein Zeichen folgt, das nicht eines der folgenden ist:

  • Ein numerisches Zeichen
  • Der Name eines der Spezialparameter (siehe Spezialparameter )
  • Ein gültiges erstes Zeichen eines Variablennamens
  • A <left-curly-bracket>('{')
  • EIN <left-parenthesis>

Das Ergebnis ist nicht angegeben.

"Nicht spezifiziert" ist hier ein besonderer Begriff, der dies bedeutet

  1. Eine konforme Shell kann in diesem Fall ein beliebiges Verhalten wählen
  2. Eine konforme Anwendung kann sich nicht auf ein bestimmtes Verhalten stützen

In Ihrem Beispiel echo ab$, das $ nicht durch , gefolgt jeden Charakter , so dass diese Regel nicht gilt und die nicht näher bezeichnet Ergebnis wird nicht aufgerufen. Es gibt einfach keine Erweiterung, die von der$ , so dass sie buchstäblich vorhanden und ausgedruckt ist.

Wo es würde gelten in unserem dritten Fall von oben: echo a$+b. Hier $wird , gefolgt von +, die nicht eine Zahl ist , spezieller Parameter ( @, *, #, ?, -, $, !, oder 0), Start eines variablen Namen (Strich oder eine alphabetischen vom tragbaren Zeichensatz ), oder eine der Klammern. In diesem Fall ist das Verhalten nicht angegeben: Eine konforme Shell darf einen speziellen Parameter erfinden, der +zum Erweitern aufgerufen wird , und eine konforme Anwendung sollte nicht davon ausgehen, dass die Shell dies nicht tut . Die Shell könnte auch alles andere tun, einschließlich der Meldung eines Fehlers.

Zum Beispiel interpretiert$+bb zsh, auch im POSIX-Modus, als "is variable set" und setzt entweder 1 oder 0 an seine Stelle. Es hat auch Erweiterungen für ~und =. Das ist konformes Verhalten.

Ein anderer Ort, an dem dies passieren könnte, ist echo "a$ b". Auch hier darf die Shell tun, was sie will, und Sie als Autor des Skripts sollten die Option " $Wenn Sie eine wörtliche Ausgabe wünschen" umgehen. Wenn Sie dies nicht tun, funktioniert es möglicherweise, aber Sie können sich nicht darauf verlassen. Dies ist der absolute Buchstabe der Spezifikation, aber ich glaube nicht, dass diese Art von Granularität beabsichtigt oder in Betracht gezogen wurde.


in Summe

  • echo ab$: Literalausgabe, vollständig spezifiziert
  • echo a$ b: Literalausgabe, vollständig spezifiziert
  • echo a$ b$: Literalausgabe, vollständig spezifiziert
  • echo a$b: Erweiterung des Parameters b, vollständig spezifiziert
  • echo a$-b: Erweiterung spezieller Parameter -, vollständig spezifiziert
  • echo a$+b: unspezifiziertes Verhalten
  • echo "a$ b": unspezifiziertes Verhalten

Für ein $am Ende eines Wortes darf man sich auf das Verhalten verlassen und es muss wörtlich behandelt und echoals Teil seines Arguments an den Befehl weitergegeben werden. Dies ist eine Konformitätsanforderung an die Shell.

Michael Homer
quelle
Kommentare sind nicht für längere Diskussionen gedacht. Diese Unterhaltung wurde in den Chat verschoben .
Terdon
@MichaelHomer Wäre echo $auch wörtlich und vollständig spezifiziert?
Harold Fischer
@HaroldFischer Ja
Michael Homer
Wohin echo "$"und echo "a b$"fallen?
Harold Fischer