Qu'est-ce que le fractionnement de mots? Pourquoi est-ce important dans la programmation shell?

16

Je suis confus quant au rôle que joue le fractionnement de mots zsh. Je n'ai pas été exposé à ce concept lors de la programmation en C, Python ou MATLAB, et cela a déclenché mon intérêt de savoir pourquoi le fractionnement de mots semble être quelque chose de spécifique à la programmation shell.

J'ai déjà lu sur le fractionnement de mots sur ce site et sur d'autres sites, mais je n'ai pas trouvé d'explication claire du concept. Wikipedia a une définition du fractionnement de mots mais ne semble pas avoir de références sur la façon dont il s'applique aux shells Unix.

Voici un exemple de ma confusion dans zsh:

Dans la FAQ Z Shell , j'ai lu ce qui suit:

3.1: Pourquoi ne $varvar="foo bar"pas ce que je pense?

Dans la plupart des dérivés Bourne-shell, les variables de plusieurs mots telles que var="foo bar" sont divisées en mots lorsqu'elles sont passées à une commande ou utilisées dans une for foo in $varboucle. Par défaut, zsh n'a pas ce comportement: la variable reste intacte. (Ce n'est pas un bug! Voir ci-dessous.) L'option SH_WORD_SPLITexiste pour assurer la compatibilité.

Cependant, dans le manuel Z Shell , j'ai lu ce qui suit:

SH_WORD_SPLIT (-y) <K> <S>

Entraîne le fractionnement des champs à effectuer des extensions de paramètres sans guillemets. Notez que cette option n'a rien à voir avec le fractionnement de mots. (Voir Extension des paramètres.)

Pourquoi dit-il que cela SH_WORD_SPLITn'a rien à voir avec le fractionnement de mots? Le mot ne divise-t-il pas précisément de quoi il s'agit?

Amelio Vazquez-Reina
la source

Réponses:

22

Les premiers shells n'avaient qu'un seul type de données: les chaînes. Mais il est courant de manipuler des listes de chaînes, généralement lors du passage de plusieurs noms de fichier comme arguments à un programme. Un autre cas d'utilisation courant pour le fractionnement est lorsqu'une commande génère une liste de résultats: la sortie de la commande est une chaîne, mais les données souhaitées sont une liste de chaînes. Pour stocker une liste de noms de fichiers dans une variable, vous devez mettre des espaces entre eux. Ensuite, un script shell comme celui-ci

files="foo bar qux"
myprogram $files

appelé myprogramavec trois arguments, car le shell divise la chaîne $filesen mots. À l'époque, les espaces dans les noms de fichiers étaient interdits ou largement considérés comme non terminés.

Le shell Korn a introduit des tableaux: vous pouvez stocker une liste de chaînes dans une variable. Le shell Korn est resté compatible avec le shell Bourne alors établi, de sorte que les extensions de variables nues ont continué à être divisées en mots, et l'utilisation de tableaux nécessitait une surcharge syntaxique. Vous écririez l'extrait ci-dessus

files=(foo bar qux)
myprogram "${files[@]}"

Zsh avait des tableaux depuis le début, et son auteur a opté pour une conception de langage plus saine au détriment de la compatibilité descendante. Dans zsh (selon les règles d'expansion par défaut), il $varn'y a pas de division de mot; si vous voulez stocker une liste de mots dans une variable, vous devez utiliser un tableau; et si vous voulez vraiment séparer les mots, vous pouvez écrire $=var.

files=(foo bar qux)
myprogram $files

De nos jours, vous devez gérer les espaces dans les noms de fichiers, à la fois parce que de nombreux utilisateurs s'attendent à ce qu'ils fonctionnent et parce que de nombreux scripts sont exécutés dans des contextes sensibles à la sécurité où un attaquant peut contrôler les noms de fichiers. Le fractionnement automatique des mots est donc souvent une nuisance; d'où mon conseil général de toujours utiliser des guillemets doubles, c'est-à-dire d'écrire "$foo", à moins que vous ne compreniez pourquoi vous avez besoin de séparer les mots dans un cas d'utilisation particulier. (Notez que les extensions de variables nues subissent également un globbing.)

Gilles 'SO- arrête d'être méchant'
la source
Merci Gilles, c'est vraiment utile! Est-il exact de dire qu'en gros, le fractionnement de mots convertit les chaînes du formulaire "word1 word2 word3"en listes / tableaux du formulaire "word1" "word2" "word3"? J'ai également mis à jour l'OP avec une source spécifique de confusion dans zsh.
Amelio Vazquez-Reina
1
@intrpc Le "fractionnement de mots" ne se divise pas en mots en langage naturel mais en $IFScaractères. Par conséquent, "division de champ" est un meilleur nom. Mais le «dédoublement de mots» est souvent utilisé pour ce concept dans la littérature sur les coques. La documentation zsh chipote sur les mots.
Gilles 'SO- arrête d'être méchant'
1
Voir aussi rc(le shell plan9, également porté sur Unix) pour une conception encore meilleure que zsh en ce qui concerne les variables et les tableaux.
Stéphane Chazelas
3

Le fractionnement de mots n'est pas vraiment spécifique au shell.

La plupart des programmes qui doivent analyser la saisie de texte utilisent une première forme de fractionnement de mots. Cela se fait avant d'identifier à partir de ces "mots", les nombres, les opérateurs, les chaînes, les jetons et toutes les entités similaires dont ils ont besoin pour traiter.

Ce qui est spécifique aux shells, c'est qu'ils doivent construire correctement la liste d'arguments des commandes appelées (C argc / argv, python sys.argv), y compris le passage d'arguments avec des espaces intégrés, des arguments vides, des délimiteurs personnalisés, etc. De nombreux shells utilisent la variable IFS pour y permettre une certaine flexibilité.

jlliagre
la source
3

Dans ce cas spécifique de Zsh, la division des mots est définie légèrement différemment de la division des champs.

Considérez prog a b c, il passera trois arguments, peu importe comment vous le définissez IFS. C'est le dédoublement des mots .

Si vous le faites A="a b c"; prog $A, il passera trois arguments si IFSinclut l'espace ou un argument sinon. C'est le fractionnement de champ .

Les définitions ici sont subtiles. Ce que le document Zsh essaie de dire, c'est que, même si vous désactivez cette option, vous prog a b cobtiendrez toujours des arguments séparés (ce à quoi les gens s'attendent toujours).

Hot.PxL
la source
1
Bart Schaefer, un développeur de longue date de zsh, confirme que c'est bien le sens voulu de ce texte .
Stéphane Chazelas