Pourquoi le tilde (~) ne se développe-t-il pas entre guillemets?

54

Selon cette réponse et ma propre compréhension, le tilde s'étend au répertoire de base:

$ echo ~
/home/braiam

Maintenant, chaque fois que je veux que l'extension du shell fonctionne, c'est-à-dire en utilisant des noms de variables tels que $FOO, et que les caractères inattendus, les espaces, etc. ne soient pas interrompus, il convient d'utiliser des guillemets doubles ":

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

Pourquoi cette extension ne fonctionne-t-elle pas avec le tilde?

$ echo ~/some/path
/home/braiam/some/path
$ echo "~/some/path"
~/some/path
Braiam
la source
3
Notez également que ceci présente une incohérence lorsqu’on fournit un argument de programme sur une ligne de commande qui --path ~/myfiles’agrandit sur un argument de commande mais --path=~/myfilene le fait pas.
Ángel
Connexes: Est
Stéphane Chazelas
Une variante de ce thème est unix.stackexchange.com/questions/279565 .
JdeBP

Réponses:

45

La raison, parce que dans les guillemets doubles, tilde ~n’a pas de signification particulière, elle est traitée comme littérale.

POSIX définit les guillemets doubles comme:

Les caractères entre guillemets ("") conservent la valeur littérale de tous les caractères compris entre guillemets, à l'exception du signe dollar, de la guillemet et de la barre oblique inverse,

...

L'application doit faire en sorte qu'un guillemet double soit précédé d'une barre oblique inverse à inclure entre guillemets. Le paramètre '@' a une signification particulière entre guillemets

À l' exception $, `, \et @, d' autres personnages sont traités comme littéral à l' intérieur des guillemets doubles.

cuonglm
la source
9
Dans ce cas, je suppose que vous devriez utiliser $HOME.
Seth
11
Ou vous pouvez simplement ne pas citer le ~, par exemplels -l ~/"My Documents"
Andrew Medico
C'est très non intuitif. Quelle est la raison pour laquelle ils ont choisi de faire cela? (Cette réponse ne donne pas réellement la raison, mais indique simplement la norme, mais la norme a probablement été écrite de cette façon pour une raison .)
iconoclaste le
1
@iconoclast si vous voulez vraiment un "pourquoi ils ont été implémentés de cette façon", lisez plutôt la réponse de Stéphane .
Braiam
2
Ainsi, @iconoclast, pourquoi est le bleu du ciel? :) :) :)
Jesse Chisholm Le
32

Le développement de tilde est défini par POSIX comme suit:

A « préfixe tilde » se compose d'un unquoted <tilde> caractère au début d'un mot, suivi de l' ensemble des caractères précédant le premier unquoted <slash> dans le mot, ou tous les caractères dans le mot , s'il n'y a pas < slash>. Dans une assignation, plusieurs préfixes tilde peuvent être utilisés: [...] suivant le signe <equals-sign> de l'affectation, après tout <colon> sans guillemets, ou les deux. [...] Si aucun des caractères du préfixe tilde n'est cité, les caractères du préfixe tilde suivant le <tilde> sont traités comme un nom de connexion possible de la base de données utilisateur. [...] Si le nom de connexion est null (c'est-à-dire que le préfixe tilde ne contient que le tilde), le préfixe tilde est remplacé par la valeur de la variable HOME. Si HOME n'est pas défini, les résultats ne sont pas spécifiés. [...]

Donc, la réponse la plus courte est "parce que c'est défini ainsi": citer l'un des caractères du préfixe, y compris le ~, supprime le développement.

Il définit également le développement comme résultant toujours en un seul mot, il serait donc inutile de citer:

Le nom de chemin résultant de l’agrandissement du tilde doit être traité comme si il était cité pour éviter qu’il ne soit altéré par la division du champ et l’extension du nom de chemin.

Là où une partie du chemin nécessite une citation, mais le reste est un préfixe tilde, vous pouvez combiner le développement de tilde et une citation ordinaire:

$ cat ~/"file name with spaces"

Sur le "pourquoi" plus large: comme il n’ya pas d’utilisation concevable pour le fractionnement de mots ~, cela devrait être le comportement par défaut, plutôt que d’exiger qu’il soit cité. Parce qu'il n'est pas nécessaire de le citer, donner ~une signification spéciale entre guillemets serait une complication inutile. Et, bien sûr, des raisons historiques signifient que cela ne pourrait pas être changé maintenant même si cela était souhaitable.

Michael Homer
la source
Selon ce guide , l'expansion du tilde se produit avant la séparation des espaces. Existe-t-il un moyen de développer en toute sécurité une extension de tilde, même si votre répertoire personnel contient des espaces? Normalement, bien sûr, vous feriez ce genre de chose avec "".
Lucretiel
L'expansion est un seul mot; voir le deuxième passage cité dans la réponse.
Michael Homer
23

~ provient du C-shell, bien avant qu'il ne soit ajouté au shell Korn, puis ajouté à la spécification du shell POSIX.

Dans le C-shell, il y ~avait un opérateur de déplacement (développé par la même routine que celle *.txtpar exemple), donc, comme le reste du déplacement, il n'était pas exécuté entre guillemets.

Stéphane Chazelas
la source
11

Bien que cela ne réponde pas pourquoi il est conçu de cette façon, vous utilisez $HOMEplutôt si vous devez remplacer, car c'est essentiellement ce que vous faites ~.

$ echo "$HOME/some/path"
/home/braiam/some/path
fusionne
la source
6
cela ne fonctionne pas avec~otheruser
Johannes Kuhn
2
C'est vrai, mais vous pourriez le faire: THEM = ~ otheruser puis utilisez "$ THEM / some / path"
fusionne le
1
La solution de contournement pour ~otherusermontre quelle mauvaise idée était de traiter ~différemment les variables et autres éléments développés entre guillemets.
iconoclast