Warum wird die Tilde (~) nicht in doppelte Anführungszeichen gesetzt?

54

Nach dieser Antwort und meinem eigenen Verständnis wird die Tilde in das Ausgangsverzeichnis erweitert:

$ echo ~
/home/braiam

Nun, wann immer ich möchte, dass die Shell-Erweiterung funktioniert, dh wenn Variablennamen wie verwendet $FOOwerden und unerwartete Zeichen, Leerzeichen usw. nicht unterbrochen werden, sollte man doppelte Anführungszeichen verwenden ":

$ FOO="some string with spaces"
$ BAR="echo $FOO"
$ echo $BAR
echo some string with spaces

Warum funktioniert diese Erweiterung nicht mit der Tilde?

$ echo ~/some/path
/home/braiam/some/path
$ echo "~/some/path"
~/some/path
Braiam
quelle
3
Beachten Sie auch, dass dies zu Inkonsistenzen führt, wenn ein Programmargument in der Befehlszeile angegeben wird, das in einem Befehlsargument --path ~/myfileerweitert wird, dies --path=~/myfilejedoch nicht tut.
Ángel
Siehe auch: Ist ~ immer gleich $ HOME
Stéphane Chazelas
Eine Variation dieses Themas ist unix.stackexchange.com/questions/279565 .
JdeBP

Antworten:

45

Der Grund dafür ist, dass Tilde in doppelten Anführungszeichen ~keine besondere Bedeutung hat und als wörtlich behandelt wird.

POSIX definiert doppelte Anführungszeichen als:

Das Einschließen von Zeichen in doppelte Anführungszeichen ("") behält den Literalwert aller Zeichen in doppelten Anführungszeichen bei, mit Ausnahme der Zeichen Dollarzeichen, Backquote und Backslash.

...

Der Antrag muss sicherstellen, dass vor einem doppelten Anführungszeichen ein Backslash steht, der in doppelte Anführungszeichen eingeschlossen wird. Der Parameter '@' hat in doppelten Anführungszeichen eine besondere Bedeutung

Außer $, `, \und @, andere Zeichen als wörtliche in doppelten Anführungszeichen behandelt.

cuonglm
quelle
9
In diesem Fall sollten Sie verwenden $HOME.
Seth
11
Oder Sie können einfach nicht zitieren ~, zum Beispiells -l ~/"My Documents"
Andrew Medico
Dies ist sehr nicht intuitiv. Was ist der Grund, warum sie sich dafür entschieden haben? (Diese Antwort gibt eigentlich nicht den Grund an, sondern zeigt nur auf die Norm, aber vermutlich wurde die Norm aus einem bestimmten Grund so geschrieben .)
iconoclast
1
@iconoclast Wenn du wirklich wissen willst, warum sie auf diese Weise implementiert wurden, lies stattdessen die Antwort von Stephane .
Braiam
2
Also, @iconoclast, warum ist der Himmel blau? :) :) :)
Jesse Chisholm
32

Die Tilde-Erweiterung wird von POSIX definiert als:

Ein "Tilde-Präfix" besteht aus einem nicht in Anführungszeichen stehenden <Tilde> -Zeichen am Wortanfang, gefolgt von allen Zeichen vor dem ersten nicht in Anführungszeichen stehenden <Schrägstrich> im Wort oder allen Zeichen im Wort, wenn kein <vorhanden ist Schrägstrich>. In einer Zuweisung können mehrere Tilde-Präfixe verwendet werden: [...] nach dem Gleichheitszeichen der Zuweisung, nach einem nicht zitierten Doppelpunkt oder beidem. [...] Wenn keines der Zeichen im Tilde-Präfix in Anführungszeichen gesetzt wird, werden die Zeichen im Tilde-Präfix nach der <Tilde> als möglicher Anmeldename aus der Benutzerdatenbank behandelt. [...] Wenn der Anmeldename null ist (dh das Tilde-Präfix enthält nur die Tilde), wird das Tilde-Präfix durch den Wert der Variablen HOME ersetzt. Wenn HOME nicht festgelegt ist, werden die Ergebnisse nicht angegeben. [...]

Die kürzeste Antwort lautet also "weil es so definiert ist": Das Zitieren eines der Zeichen im Präfix, einschließlich des ~, unterdrückt die Erweiterung.

Außerdem wird die Erweiterung so definiert, dass sie immer ein einzelnes Wort ergibt, sodass keine Anführungszeichen erforderlich sind:

Der aus der Tilde-Erweiterung resultierende Pfadname wird so behandelt, als ob er in Anführungszeichen gesetzt wäre, um zu verhindern, dass er durch Feldaufteilung und Pfadnamen-Erweiterung geändert wird.

Wenn für einen Teil des Pfads Anführungszeichen erforderlich sind, der Rest jedoch ein Tilde-Präfix ist, können Sie die Tilde-Erweiterung und das normale Anführen von Anführungszeichen direkt kombinieren:

$ cat ~/"file name with spaces"

Was das "Warum" angeht: Da es keine vorstellbare Verwendung für das Teilen von Wörtern ~gibt, sollte dies das Standardverhalten sein, anstatt dass es in Anführungszeichen gesetzt wird. Da es nicht erforderlich ist, es zu zitieren, ~wäre es eine unnötige Komplikation, in Anführungszeichen eine besondere Bedeutung zu setzen. Und natürlich kann es aus historischen Gründen nicht geändert werden, selbst wenn dies wünschenswert wäre.

Michael Homer
quelle
Nach dieser Bash-Anleitung erfolgt die Tilde-Erweiterung vor der Trennung von Leerzeichen. Gibt es eine Möglichkeit, eine Tilde-Erweiterung sicher durchzuführen, auch wenn Ihr Home-Verzeichnis Leerzeichen enthält? Normalerweise macht man so etwas natürlich mit "".
Lucretiel
Die Erweiterung ist ein einziges Wort; siehe die zweitzitierte Passage in der Antwort.
Michael Homer
23

~ stammt aus der C-Shell, lange bevor sie der Korn-Shell und später der POSIX-Shell-Spezifikation hinzugefügt wurde.

In der C-Shell ~befand sich ein Globbing-Operator (erweitert durch die gleiche Routine wie derjenige, der *.txtzum Beispiel erweitert wurde), so dass der Rest des Globbing nicht in doppelten Anführungszeichen ausgeführt wurde.

Stéphane Chazelas
quelle
11

Dies ist zwar keine Antwort darauf, warum es so konzipiert ist, aber Sie verwenden es, $HOMEwenn Sie es ersetzen müssen, da dies im Wesentlichen das ist, was es ~tut.

$ echo "$HOME/some/path"
/home/braiam/some/path
verschmilzt
quelle
6
Dies funktioniert nicht mit~otheruser
Johannes Kuhn
2
Richtig, aber Sie könnten es tun: THEM = ~ otheruser, dann verwenden Sie "$ THEM / some / path"
meldet sich
1
Die Problemumgehung für ~otheruserzeigt, wie schlecht es war, ~Variablen und andere Dinge, die in doppelte Anführungszeichen eingeschlossen sind , anders zu behandeln .
Bilderstürmer