Est-ce que ~ est toujours égal à $ HOME

40

Je sais que cela a probablement déjà été demandé, mais je ne pouvais pas le trouver avec Google.

Donné

  • Noyau Linux
  • Aucune configuration qui change $ HOME
  • frapper

Sera ~ == $HOMEvrai?

PythonNut
la source
3
Je crois que oui, mais ce n’est pas un problème spécifique à Linux. Je pense plutôt que ~cela sera équivalent à $HOMEn'importe quel environnement POSIX; mais je peux me tromper.
HalosGhost
4
Malgré les réponses ci-dessous… pas toujours. Comparez echo "~"et echo "$HOME".
Sparhawk
@Sparhawk Attendez, alors 1 + 1 n'est pas 2? C'est un complot! Le gouvernement nous cache quelque chose! : P
Poignée de porte
1
@Sparhawk, vous remarquerez que le PO n'a en fait pas cité le ~ou $HOME. : P
HalosGhost
2
@ HalosGhost Ah, bon point. (En outre, j'ai remarqué plus tard que la réponse de Michael Homer mentionnait "un simple non cité ~".) Quoi qu'il en soit, il convient de garder à l'esprit le lecteur non averti, comme moi.
Sparhawk

Réponses:

46

Ce qu'il est important de comprendre, c'est que l' ~expansion est une fonctionnalité du shell (de certains shell), ce n'est pas un caractère magique qui désigne votre répertoire personnel, où qu'il soit utilisé.

Il est développé (par le shell, qui est une application utilisée pour interpréter les lignes de commande), de la même manière que $varsa valeur est développée dans certaines conditions lorsqu'il est utilisé dans une ligne de commande shell avant l'exécution de la commande.

Cette fonctionnalité est apparue pour la première fois dans le C-shell à la fin des années 1970 (le shell Bourne ne l’avait pas, pas plus que son prédécesseur, le shell Thompson), a ensuite été ajoutée au shell Korn (un nouveau shell construit sur le shell Bourne dans le Années 80). Il a finalement été normalisé par POSIX et est maintenant disponible dans la plupart des shells, y compris ceux non-POSIX fish.

Du fait de son utilisation très répandue dans les shells, certaines applications non-shell le reconnaissent également comme désignant le répertoire de base. C'est le cas de nombreuses applications dans leurs fichiers de configuration ou de leur propre ligne de commande ( mutt, slrn, vim...).

bashspécifiquement (qui est le shell du projet GNU et qui est largement utilisé dans de nombreux systèmes d’exploitation basés sur Linux), quand elle est invoquée en tant que shsuit les règles POSIX concernant le ~développement, et dans les zones non spécifiées par POSIX, se comporte principalement comme le shell Korn (de dont il s’agit d’un clone partiel).

Alors que $varest étendu dans la plupart des endroits (sauf dans les guillemets simples), l' ~expansion, après-coup, n'est développée que dans quelques conditions spécifiques.

Il est développé lorsque son propre argument est utilisé dans des contextes de liste, dans des contextes dans lesquels une chaîne est attendue.

Voici quelques exemples d’extensions bash:

  • cmd arg ~ other arg
  • var=~
  • var=x:~:x(requis par POSIX, utilisé pour des variables telles que PATH, MANPATH...)
  • for i in ~
  • [[ ~ = text ]]
  • [[ text = ~ ]](L’expansion ~est considérée comme une tendance chez AT & T kshmais pas bashdepuis la 4.0).
  • case ~ in ~) ...
  • ${var#~} (mais pas dans d'autres coquilles)
  • cmd foo=~(mais pas quand invoqué sh, et seulement quand ce qui est à gauche =est formé comme un bashnom de variable sans guillemets )
  • cmd ~/x (requis par POSIX évidemment)
  • cmd ~:x(mais pas x:~:xou x-~-x)
  • a[~]=foo; echo "${a[~]} $((a[~]))" (pas dans d'autres coquilles)

Voici quelques exemples où ce n'est pas développé:

  • echo "~" '~'
  • echo ~@ ~~(notez également que cela ~uest destiné à être étendu au répertoire de base de l'utilisateur u).
  • echo @~
  • (( HOME == ~ )), $(( var + ~ ))
  • avec extglob: case $var in @(~|other))...(si case $var in ~|other)c'est OK).
  • ./configure --prefix=~(comme --prefixn'est pas un nom de variable valide)
  • cmd "foo"=~(en bash, à cause des guillemets).
  • comme lorsqu'il est appelé sh: export "foo"=~, env JAVA_HOME=~ cmd...

Quant à ce qui se développe: ~seul se développe au contenu de la HOMEvariable, ou lorsqu'elle n'est pas définie, au répertoire de base de l'utilisateur actuel dans la base de données de comptes (en tant qu'extension puisque POSIX laisse ce comportement indéfini).

Il convient de noter que, dans ksh88 et dans les bashversions antérieures à 4.0, l’extension tilde était globalisée (génération de nom de fichier) dans des contextes de liste:

$ bash -c 'echo "$HOME"'
/home/***stephane***
$ bash -c 'echo ~'
/home/***stephane*** /home/stephane
$ bash -c 'echo "~"'
~

Cela ne devrait pas être un problème dans les cas habituels.

Notez que, comme il est développé, le même avertissement s’applique aux autres formes d’expansion.

cd ~

Ne fonctionne pas si $HOMEcommence avec -ou contient des ..composants. Ainsi, même s'il est très peu probable de faire une différence, à proprement parler, il convient d'écrire:

cd -P -- ~

Ou même:

case ~ in
  (/*) cd -P ~;;
  (*) d=~; cd -P "./$d";;
esac

(pour couvrir des valeurs de $HOMEcomme -, +2...) ou simplement:

cd

(comme cd vous mène à votre répertoire personnel sans aucun argument)

D'autres coquilles ont des ~expansions plus avancées . Par exemple, dans zsh, nous avons:

  • ~4, ~-, ~-2(Avec l' achèvement) utilisé pour élargir les répertoires dans votre pile de répertoires (les endroits que vous avezcd à avant).
  • répertoires nommés dynamiques . Vous pouvez définir votre propre mécanisme pour décider de la manière dont elle ~somethingsera développée.
Stéphane Chazelas
la source
25

Dans n'importe quelle version de Bash sur n'importe quel système, oui . ~en tant que terme seul est défini pour s'étendre à:

La valeur de $ HOME

donc ce sera toujours le même que ce qui $HOMEest au shell actuel. Il existe plusieurs autres extensions de tilde, telles que le répertoire personnel de ~userfor user, mais une seule non citée ~seule sera toujours étendue à "$HOME".

Notez que le comportement de ~et $HOMEpeut être différent dans certains cas: en particulier, si $HOMEcontient des espaces (ou d’autres caractères IFS ), alors $HOME(sans citation) se développera en plusieurs mots, alors qu’il ~s’agit toujours d’un seul mot. ~se développe de manière équivalente à "$HOME"(cité).

En ce qui concerne votre question spécifique:

[[ $HOME == ~ ]]

est toujours vrai, car [[ supprime le fractionnement des mots. [[ ~ == $HOME ]peut ne pas l'être s'il HOMEcontient des caractères de correspondance de motif , mais [[ ~ == "$HOME" ]](c'est-à-dire entre guillemets "$HOME") est toujours vrai. Son utilisation entre crochets simples peut constituer une erreur de syntaxe pour les valeurs HOMEcontenant des espaces ou des caractères spéciaux. Pour toute configuration de répertoire de base sensible ~et "$HOME"sont les mêmes et comparent comme égaux.


Stéphane Chazelas a noté un cas dans les commentaires où ~et a $HOMEdonné des valeurs différentes: si unset HOMEvous utilisez ~Bash, vous appelez getpwuidpour lire une valeur dans la base de données de mots de passe. Ce cas est exclu par votre condition de ne pas avoir changé de configuration $HOME, mais je le mentionnerai ici par souci d'exhaustivité.

Michael Homer
la source
1
Cependant, /bin/shpourrait ne pas être bash. Je ne suis pas sûr que les shspécifications de Posix en parlent~
Basile Starynkevitch le
1
POSIX spécifie ~. ~n'était pas dans le shell de Thomson ou Bourne (qui à leur époque étaient disponibles en tant que /bin/sh). Ce n'est pas dans rcou ses dérivés (où il est utilisé pour autre chose)
Stéphane Chazelas
5
Dans quelques shells, y compris bash, si HOMEest non défini, se ~développe dans le répertoire de base de l'utilisateur à partir de la base de données passwd. Donc, c'est un cas où ~ne peut pas augmenter à la valeur de $HOME.
Stéphane Chazelas
1
Notez que, bashavant bash4, effectuait un déplacement sur l'expansion du tilde (essayez HOME='/*' bash -c 'echo /*'). Donc HOME=/*; [ "$HOME" = ~ ], retournerait une erreur là-bas.
Stéphane Chazelas
4
@cuonglm j'ai vérifié le code source. Il appelle finalement , qui utilise sur toutes les plates-formes, sauf Tandem . get_current_user_infogetpwuid
Michael Homer