Pourquoi ne puis-je pas cd sur un tilde cité ('~')?

33

En écrivant mon premier scénario, je suis donc sûr que c'est une question fondamentale, mais quelqu'un peut-il m'expliquer pourquoi je peux:

cd ~
cd bin
cd ~/bin
cd 'bin'

Mais non

cd '~'
cd '~/bin'

J'ai besoin d' cdun chemin de répertoire avec un espace dans l'un des noms de répertoire, j'ai donc besoin des guillemets (c'est Windows Program Filessous le vin). Je peux le contourner avec deux cdcommandes, mais pourquoi ne puis-je pas mettre ~de guillemets?

Si je tape cd '~'(ou cd "~") je reçois:

bash: cd: ~: No such file or directory
B.Tanner
la source
29
Posez-vous la question suivante: si cela ne fonctionnait pas , comment accéderiez-vous cdà un répertoire nommé ~?
Jörg W Mittag
2
Sidenote, si vous écrivez un script, vous devriez plutôt utiliser des chemins absolus et les éviter cdcomplètement. Utilisez des variables pour stocker les noms de chemins que vous ne voulez pas taper plusieurs fois, par exemplepf=~/.wine/drive_c/Program\ Files/; cp /path/to/file "$pf"
dessert
8
@ jamesqf: Pourquoi un système sensé présumerait-il de savoir mieux que moi ce que je veux nommer mes fichiers et mes répertoires? De plus, je n'ai jamais compris pourquoi Unix utilisait la signalisation magique dans la bande des séparateurs de composants de chemin et des terminateurs de chemin. Quel est le problème avec un fichier / répertoire nommé /ou NUL?
Jörg W Mittag
3
@ JörgWMittag probablementcd ./~
k_g
2
@jamesqf Juste pour noter qu'historiquement, les systèmes de fichiers Unix autorisaient n'importe quel caractère dans un nom de fichier à part '/' (séparateur de chemin) et '\ 0' (NUL - caractère de fin de chaîne) - comme le note Jorg. Pas d'autres restrictions. Il y a eu beaucoup d'implémentations de systèmes de fichiers Unix, donc introduire des restrictions dans n'importe lequel d'entre eux aurait brisé la compatibilité et augmenté la complexité - et aurait été perçu comme "étrange"! Et l'extension '~' n'a été introduite que relativement récemment dans csh et plus largement dans bash, les fichiers / répertoires avec des caractères '~' ne sont pas inconnus (par exemple, myfile ~ en tant que sauvegarde pour myfile).
SusanW

Réponses:

79

Comme @karel l'a noté dans sa réponse, il ~s'agit d'un caractère spécial développé par Bash dans le répertoire de base de l'utilisateur actuel. Reportez-vous au manuel de Bash sur "Extension de tilde" ou recherchez le titre "Extension de tilde" dans la page de manuel ( man bash).

N'importe quel type de citation ~empêche le développement de ce tilde.


Pour répondre à votre question sur la manière dont vous pouvez toujours l'utiliser pour cdcréer un répertoire avec des espaces dans son nom, il existe plusieurs alternatives:

  • Omettez les guillemets et échappez les espaces avec des barres obliques inverses:

    cd ~/foo/spaces\ are\ cool/bar
  • Citez le reste du chemin, mais omettez-les autour du tilde et de la première barre oblique:

    cd ~/"foo/spaces are cool/bar"

    Comme vous le voyez, vous pouvez concaténer des chaînes citées et non citées dans Bash en les écrivant simplement les unes à côté des autres, sans espace entre elles.

  • Utilisez la variable d'environnement à la $HOMEplace du tilde, qui est toujours développé à l'intérieur de "guillemets doubles" (mais pas de "guillemets simples"):

    cd "$HOME/foo/spaces are cool/bar"
Byte Commander
la source
3
@ rexkogitans ~'/...'ne fonctionnera pas et n'est pas ce que cette réponse a. ~/'...'ou ~/"..."va travailler.
hvd
tld; dr: parce que c'est la syntaxe du shell
Sergiy Kolodyazhnyy
@hvd merci. Correction d'une faute de frappe. Ceci est la réponse la plus complète et explique également comment résoudre ce que le PO veut faire. ~/'path'est le chemin à parcourir.
rexkogitans
1
@hvd juste un peu de curiosité, pourquoi ne pas ~'/...'travailler? La barre oblique n'est pas un caractère spécial, il semble donc qu'elle devrait fonctionner à l'intérieur ou à l'extérieur des guillemets.
Kodos Johnson
6
@KodosJohnson Consultez la section de la page de manuel Bash sur "Expansion de Tilde". Le paragraphe pertinent de cela est également cité dans la réponse du dessert ci-dessous. TL; DR: le développement du tilde a lieu si le premier caractère d'un mot est un tilde non entre guillemets, alors tout ce qui se trouve entre ce tilde et la prochaine barre oblique sans guillemets est considéré comme le "préfixe tilde". Si ce préfixe n'est pas valide, par exemple +, -, un nombre ou un nom d'utilisateur (les guillemets ne sont pas autorisés non plus), l'expansion échoue et vous obtenez un caractère ~ littéral.
Byte Commander
17

~ est un caractère spécial interprété par le shell comme le répertoire de base de l'utilisateur connecté. '~' est interprété par le shell comme un caractère littéral ~, et non comme le répertoire de base de l'utilisateur connecté, car l'enfermement d'une chaîne entre deux caractères de guillemets simples entraîne l'interprétation de cette chaîne en tant que chaîne de texte littéral.

Karel
la source
~n’est pas un alias au sens où l’ bashinterprète: les alias permettent de substituer une chaîne à un mot lorsqu’il est utilisé comme premier mot d’une commande simple. . Comme je l'explique dans ma réponse ci-dessous, c'est plutôt une expansion.
dessert
15

Ceci est une bashfonctionnalité appelée Expansion Tilde . Citant man bash:

Si un mot commence par un caractère tilde sans guillemets («~»), tous les caractères précédant la première barre oblique sans guillemets (ou tous les caractères, s'il n'y en a pas) sont considérés comme un préfixe tilde. 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. Si ce nom de connexion est la chaîne NULL, le tilde est remplacé par la valeur du paramètre shell HOME. Si HOME n'est pas défini, le répertoire de base de l'utilisateur exécutant le shell est remplacé.

Pour que l'expansion fonctionne, le caractère tilde ~doit être non mis entre guillemets, sinon le caractère est pris littéralement et cdéchoue s'il n'y a pas de répertoire nommé ~présent dans le répertoire en cours. Voir cette réponse exhaustive pour une explication de citer dans bash. Si vous devez citer une partie du chemin, vous pouvez donc:

  1. citez au moins les caractères qui ont besoin de guillemets avec des guillemets simples, p.ex.

    ~/dir' 'with' 'spaces/

    ou

    ~/'dir with spaces/'
  2. citez au moins les caractères qui nécessitent des guillemets, par exemple

    ~/dir" "with" "spaces/

    ou

    ~/"dir with spaces/"
  3. ne citez que les caractères qui nécessitent des guillemets, par exemple

    ~/dir\ with\ spaces/

Tilde Expansion a quelques fonctionnalités plus intéressantes, par exemple:

  • ~+se développe à la valeur de PWD, c'est-à-dire le répertoire de travail en cours
  • ~-se développe à la valeur de OLDPWD, c'est-à-dire le répertoire de travail précédent
  • ~john se développe dans le répertoire de base associé au nom de connexion “john”
dessert
la source
Incidemment, il est normal de «surestimer» avec des barres obliques inverses également; par exemple $ touch a; cd \a. (Je pensais que cela risquait de poser des problèmes cd \n, mais des expériences au moins sur ma version de bashsuggèrent que cela fonctionne très bien.)
LSpice
1

Explorer en utilisant la echocommande

Le moyen le plus simple d'explorer le fonctionnement de bash est d'utiliser la echocommande. En cas d' ~utilisation ceci:

$ echo ~
/home/rick
$ echo '~'
~
$ echo "~"
~
$ echo `~`
bash: /home/rick: Is a directory

Comme vous pouvez le constater, lorsque vous utilisez un guillemet simple ou que vous utilisez des guillemets doubles, ~il est interprété littéralement comme une chaîne et non développé comme une variable. Lorsque vous utilisez des backticks (`), il est exécuté en tant que commande et génère un message d'erreur.

WinEunuuchs2Unix
la source