web-dev-qa-db-fra.com

Pourquoi l'alias foo = 'echo "Ceci est une citation: \'" 'ne fonctionne pas?

Afin de me rappeler quand j'essaie d'utiliser shopt dans Zsh au lieu de setopt, j'ai créé l'alias suivant, en le testant d'abord à une invite du shell:

$ alias shopt='echo "You\'re looking for setopt. This is Z Shell, man, not Bash."'

Malgré la correspondance des guillemets simples externes et la correspondance des guillemets doubles intérieurs, et l'apostrophe étant échappée, j'ai été invité à terminer la fermeture des guillemets avec:

dquote > _

Que se passe-t-il?

Il est apparu que l'évasion était ignorée, ou qu'il fallait la double échapper à cause de plusieurs niveaux d'interprétation ... Donc, juste pour tester cette théorie, j'ai essayé de la double échapper (et de la triple échapper, etc.) marche) jusqu'à:

alias shopt='echo "You\\\\\\\\\\\\\\\\\\\\\\'re looking for setopt. This is Z Shell, man, not Bash." '

et jamais vu aucun comportement différent. Cela n'a aucun sens pour moi. Quel genre de vaudou bizarre empêche le Shell de se comporter comme je l'attends?

La solution pratique est de ne pas utiliser de guillemets pour echo, car elle n'en a pas vraiment besoin, et d'utiliser des guillemets doubles pour alias, et d'échapper à l'apostrophe pour qu'elle soit ignorée lorsque le texte est echoed. Ensuite, tous les problèmes pratiques disparaissent.

Pouvez-vous m'aider? J'ai besoin d'une solution à ce problème déroutant.

23
iconoclast

C'est zsh, homme, pas fish.

Dans zsh, comme dans tous les Bourne-like Shell (et aussi csh), les guillemets simples sont des guillemets forts, il n'y a pas d'échappatoire en eux (sauf en utilisant le rcquotes options comme indiqué par @JdeBPzsh émule rc guillemets¹). Vous ne pouvez pas avoir de guillemet simple dans une chaîne entre guillemets simples, vous devez d'abord fermer la chaîne entre guillemets simples et saisir le guillemet simple littéral à l'aide d'un autre mécanisme de guillemets (comme \ ou "):

alias shopt='echo "You'\''re looking for setopt. This is Z Shell, man, not Bash."'

Ou:

alias shopt='echo "You'"'"'re looking for setopt. This is Z Shell, man, not Bash."'

Bien que vous puissiez également faire:

alias shopt="echo \"You're looking for setopt. This is Z Shell, man, not Bash.\""

("..." sont des guillemets plus faibles à l'intérieur desquels plusieurs caractères, dont \ (ici utilisé pour échapper au ") sont encore spéciaux).

Ou:

alias shopt=$'echo "You\'re looking for setopt. This is Z Shell, man, not Bash."'

($'...' est encore un autre type de citations de ksh93, où le ' peut être échappé avec \').


¹ Dans rc, le Shell de Plan9, avec une version pour unix-like également disponible, les guillemets simples sont le seul mécanisme de citation (la barre oblique inverse et les guillemets doubles sont des caractères ordinaires là-bas), le seule façon de saisir un guillemet simple littéral avec '' entre guillemets simples, donc avec zsh -o rcquotes, vous pourriez faire:

alias shopt = 'echo "Vous recherchez setopt. C'est Z Shell, mec, pas Bash."'
43
Stéphane Chazelas

Les autres réponses expliquent bien pourquoi vous voyez ce comportement. Mais si je peux faire une suggestion sur la façon de résoudre réellement ce problème:

N'utilisez pas d'alias pour quoi que ce soit de compliqué, même à distance.

Bien sûr, vous pouvez nouer votre cerveau en nœuds en essayant de comprendre comment imbriquer N couches de guillemets, mais cela en vaut rarement la peine pour un alias. Lorsqu'un alias est suffisamment compliqué pour que sa citation devienne non triviale, passez simplement à une fonction Shell:

shopt(){
    echo "You're looking for setopt. This is Z Shell, man, not Bash."
}

Cela supprime une couche entière de guillemets, vous permet d'ajouter plus de code à la fonction Shell plus tard, et est généralement beaucoup plus facile à lire. Il permet également un contrôle beaucoup plus fin sur la façon et l'endroit où les arguments sont insérés, au lieu de l'approche alias de "remplacez simplement le début de la ligne et laissez les mots restants tomber où ils le peuvent". Par exemple, avec votre alias (corrigé), si vous saisissez ceci:

shopt -s some_opt

... alors vous obtiendrez cette sortie:

You're looking for setopt. This is Z Shell, man, not Bash. -s some_opt

Ce n'est probablement pas ce que vous vouliez. La fonction Shell consommera tous les arguments que vous lui passerez et les ignorera en silence.

13
Kevin
shopt = 'echo "You \'

Ce n'est pas du vaudou. Il s'agit du shell POSIX normal en action. Il n'y a pas de mécanisme d'échappement dans les chaînes entre guillemets simples . Ils se terminent toujours lors du prochain devis. Il existe une extension Z Shell qui fait que deux chaînes successives entre guillemets obtiennent un guillemet simple placé entre elles, que vous pourriez utiliser. Ou vous pouvez simplement terminer la chaîne entre guillemets simples, utiliser un guillemet simple échappé (ou en fait sans guillemets simples), puis démarrer une deuxième chaîne entre guillemets simples.

Ou vous ne pouviez pas utiliser de contractions dans vos messages. ☺

Lectures complémentaires

  • "guillemets simples" . Langage de commande du shell . Spécifications de base. IEEE 1003.1: 2017. The Open Group
  • "Citation" . Grammaire shell . Le manuel Z Shell.
13
JdeBP

Pour les jours où vous n'avez pas envie de combattre les guillemets, utilisez un autre personnage comme Unicode U + 2019 au lieu de ' pour les apostrophes.

Appuyez et maintenez Ctrl+Shift et tapez u2019 et ce caractère apparaîtra (euh ... selon votre région?).

% alias shopt='echo You’re looking for setopt. This is a Z Shell, woman, not Bash.'
% shopt -s dotglob
You’re looking for setopt. This is a Z Shell, woman, not Bash. -s dotglob

Une telle utilisation de (U + 2019) est correct car ce caractère est officiellement destiné à être utilisé comme apostrophe. Le standard Unicode, version 10.0 recommande explicitement une telle utilisation. La norme reconnaît que ' (U + 0027) est couramment utilisé comme apostrophe en raison de sa présence dans ASCII et sur les claviers, et semble le permettre. Mais il indique ensuite que (U + 2019) est préféré pour les apostrophes utilisées comme ponctuation (et donne une contraction comme exemple). Les seules apostrophes pour lesquelles (U + 2019) n'est pas préféré sont ceux utilisés comme signes diacritiques plutôt que comme signes de ponctuation; ce sont les mieux écrits ʼ (U + 02BC). De Apostrophes (p. 276) dans la section 6.2 de la norme:

Apostrophes

U + 0027  [~ # ~] apostrophe [~ # ~]  est le caractère le plus couramment utilisé pour l'apostrophe. Pour des raisons historiques, U + 0027 est un personnage particulièrement surchargé. En ASCII, il est utilisé pour représenter un signe de ponctuation (tel que le guillemet simple droit, le guillemet simple gauche, la ponctuation apostrophe, la ligne verticale ou le caractère premier) ou une lettre modificatrice (comme le modificateur apostrophe ou l'accent aigu). Les signes de ponctuation cassent généralement les mots; les lettres modificatrices sont généralement considérées comme faisant partie d'un mot.

Lorsque le texte est défini, U + 2019  MARQUE DE COTATION UNIQUE DROITE  est préféré comme apostrophe, mais seul U + 0027 est présent sur la plupart des claviers. Le logiciel offre généralement une fonction pour convertir automatiquement le U + 0027  [~ # ~] apostrophe [~ # ~]  à un glyphe de citation bouclé sélectionné contextuellement. Dans ces systèmes, un U + 0027 dans le flux de données est toujours représenté comme une ligne verticale droite et ne peut jamais représenter une apostrophe frisée ou un guillemet droit.

Apostrophe. U + 02BC  LETTRE MODIFICATRICE APOSTROPHE  est préférable lorsque l'apostrophe doit représenter une lettre modificatrice (par exemple, dans des translittérations pour indiquer un arrêt glottal). Dans ce dernier cas, il est également appelé une apostrophe de lettre.

Apostrophe de ponctuation. U + 2019  MARQUE DE COTATION UNIQUE DROITE  est préférable lorsque le caractère doit représenter un signe de ponctuation, comme pour les contractions: " Nous avons déjà été ici." Dans ce dernier cas, U + 2019 est également appelé apostrophe de ponctuation.

Une implémentation ne peut pas supposer que le texte des utilisateurs respecte toujours la distinction entre ces caractères. Le texte peut provenir de différentes sources, y compris le mappage à partir d'autres jeux de caractères qui ne font pas cette distinction entre l'apostrophe des lettres et l'apostrophe de ponctuation/guillemet simple droit. Dans ce cas, tous d'entre eux seront généralement représentés par U + 2019.

La sémantique d'U + 2019 dépend donc du contexte. Par exemple, s'il est entouré de lettres ou de chiffres des deux côtés, il se comporte comme un caractère de ponctuation dans le texte et ne sépare pas les mots ou les lignes.

5
Zanna

Un commentaire maintenant supprimé m'a informé et m'a mis à mi-chemin de la réponse.

Il est impossible d'échapper à un guillemet simple à l'intérieur d'une chaîne entre guillemets simples .

Cette limitation n'est pas présente dans les chaînes entre guillemets doubles, car j'échappe certainement à un guillemet simple à l'intérieur d'une chaîne entre guillemets doubles dans ma solution finale:

alias shopt="echo You\'re looking for setopt. This is Z Shell, man, not Bash."
4
iconoclast