Fish-shell: la casse spéciale PATH/MANPATH/CDPATH est bizarre ; nous avons besoin d'une solution plus générale comme les variables "liées" zsh

Créé le 11 déc. 2012  ·  52Commentaires  ·  Source: fish-shell/fish-shell

En expand.h :

/** Character for separating two array elements. We use 30, i.e. the ascii record separator since that seems logical. */
#define ARRAY_SEP 0x1e

/** String containing the character for separating two array elements */
#define ARRAY_SEP_STR L"\x1e"

Cela se traduit par :

xiaq<strong i="10">@blackie</strong> ~> set a (printf 'a\x1eb')
xiaq<strong i="11">@blackie</strong> ~> count $a
2
xiaq<strong i="12">@blackie</strong> ~> set a (printf 'a\x1fb')
xiaq<strong i="13">@blackie</strong> ~> count $a
1

Il est clair que le caractère \x1e est traité spécialement comme délimiteur d'élément.

enhancement

Tous les 52 commentaires

Le souci est-il qu'il n'y a aucun moyen de représenter \x1e ? Ou pensez-vous à des améliorations architecturales?

Je pense que le séparateur de tableau est principalement utilisé dans les tableaux persistants dans des endroits qui ne prennent que des chaînes, comme les variables universelles ou les variables d'environnement.

在 2012-12-12 à 2:09,"ridiculousfish" [email protected]写道

Le souci est-il qu'il n'y a aucun moyen de représenter \x1e ? Ou pensez-vous
sur les améliorations architecturales?

Je dirais que j'ai les deux préoccupations à l'esprit. Pour le premier, il suffit de penser à un
nom de fichier avec \x1e intégré. POSIX dit que tout sauf \0 est autorisé dans
noms de fichiers, donc c'est parfaitement possible. L'utilisation de \0 comme délimiteurs de tableau peut être
un choix légèrement meilleur, mais cela conduit à la deuxième préoccupation - c'est
fragile et manifestement erroné.

Je pense que le séparateur de tableau est principalement utilisé dans les tableaux persistants par endroits
qui ne prennent que des chaînes, comme les variables universelles ou les variables d'environnement.

Si persistant signifie "sérialisé", non. Les tableaux sont toujours stockés dans
forme délimitée par \x1e. Les tableaux d'environnement exportés sont joints par ":". Ils
sont cependant utilisés dans les variables universelles - qui, à mon humble avis, devraient être implémentées
avec une bonne évasion à la place.


Répondez directement à cet e-mail ou consultez-le sur GitHub.

Que diriez-vous d'utiliser un caractère de zone d'utilisation privée comme séparateur ? Fish en utilise déjà certains dans certains cas.

@JanKanis Ce n'est pas mieux; c'est parfaitement possible dans les noms de fichiers (en tenant compte des systèmes de fichiers utilisant des encodages natifs non utf8) et d'autres chaînes.

Je dirais qu'entre autres, "\0" est un choix _légèrement_ meilleur parmi d'autres, puisque c'est le seul caractère qu'UNIX interdit dans les noms de fichiers, mais il a toujours une mauvaise odeur pour moi. De plus, nous faisons déjà beaucoup de fractionnement et d'assemblage de tableaux, je m'attendrais à ce que l'implémentation de vrais tableaux se traduise à la fois par une meilleure architecture et moins de code.

Fish gère déjà les caractères à usage privé et les octets non valides lorsqu'il encode des chaînes externes en wchars. Ces valeurs spéciales sont encodées octet par octet dans un ensemble spécifique de caractères à usage privé que fish décode également à la sortie, donc en principe, l'utilisation d'un autre caractère à usage privé pourrait fonctionner. Cependant, je suis d'accord que l'utilisation de vrais tableaux est bien meilleure. Il y a une complication dans la communication entre fish et fishd via une socket utilisant des chaînes utf8, et fish utilise (je pense) la séquence d'échappement "\x1e" (plutôt qu'un octet 0x1e) pour séparer les éléments du tableau. Mais cela pourrait probablement être résolu en utilisant, par exemple, une séquence d'échappement privée inutilisée.

Je partage les préoccupations de xiaq, mais (pour les questions pratiques) je trouve la division implicite sur \n bien plus offensante :

a<strong i="6">@raspeball</strong> ~> count (printf 'a\x1eb')
1
a<strong i="7">@raspeball</strong> ~> count (printf 'a\nb')
2

L'interprétation du tableau (délimité par une nouvelle ligne) de la sortie du sous-processus doit être explicite et facultative !

Mais cela n'a probablement rien à voir avec le stockage sous-jacent des tableaux...

@xiaq : Quel est le problème avec l'utilisation \0 ? xargs semble l'utiliser comme son option "fiable".

Vous ne pouvez pas utiliser \0 dans les variables d'environnement, il serait donc difficile d'exporter des tableaux vers des shells enfants.

Je migre de zsh où j'utilise cette séquence pour définir la variable $LESS env de manière sensée en tirant parti de sa fonctionnalité de variables "liées":

typeset -xT LESS less ' '
less=(
    --HILITE-UNREAD
    --LONG-PROMPT
)

J'ai omis la liste complète des options par souci de concision. Dans zsh, il en résulte que $LESS env var est une liste d'options séparées par des espaces dans le tableau $less. L'équivalent en poisson entraîne la séparation des éléments par le caractère séparateur d'enregistrement (\x1e). Malgré la documentation indiquant que les éléments du tableau seront séparés par des espaces (modulo les tableaux spéciaux tels que PATH). Je dois explicitement faire une affectation qui interpole les valeurs en une seule chaîne pour obtenir le résultat attendu :

set -x LESS --HILITE-UNREAD \
    --LONG-PROMPT
set LESS "$LESS"

Pour le moment, je ne me soucie pas vraiment de savoir si \x1e est utilisé en interne pour la sérialisation des tableaux plutôt que \x00. Je me soucie que les tableaux exportés aient leurs éléments séparés par \x1e. C'est juste cassé, faux, fubar. Choisissez votre adjectif. Il est également incompatible avec la solution de contournement susmentionnée et le comportement documenté. Ce problème devrait être marqué comme un bogue à mon humble avis.

PS, Nulle part dans la documentation l'utilisation du caractère séparateur d'enregistrement (\x1e) n'est mentionnée. Ce qui est un autre problème.

@krader1961 Merci pour ce partage. Il n'y a pas de convention Unix standard pour les variables d'environnement de type liste - certaines sont délimitées par deux-points, d'autres sont délimitées par des espaces. fish utilise \x1e pour pouvoir distinguer ses propres tableaux.

Pouvez-vous s'il vous plaît nous indiquer la documentation erronée?

Comment pensez-vous que les tableaux soient exportés - deux-points, espaces, retours à la ligne, autre chose ? Les poissons doivent-ils également tokeniser les variables d'environnement sur ce personnage ?

Il semble que less attend des arguments délimités par des espaces. La solution de contournement la plus simple est probablement set -x LESS '--HILITE-UNREAD --LONG-PROMPT' , etc.

Il n'y a pas de norme pour les variables d'environnement de type liste car, par définition, elles sont une séquence arbitraire d'octets composée d'une clé et d'une valeur séparées par un signe égal et terminées par un octet nul. Ils n'ont même pas besoin d'être des caractères imprimables. La seule convention largement acceptée pour un niveau d'abstraction plus élevé est celle établie par la fonction execlp() pour la variable PATH env.

La documentation est erronée dans la mesure où elle ne fait aucune mention de l'utilisation de \x1E, \036, 30 ou du caractère "séparateur d'enregistrements" pour séparer les éléments d'un tableau lors de l'exportation d'un var avec plus d'un élément. La documentation indique que

..., and array variables will be concatenated using the space character.

Cela provient de la section "Extension variable" dans http://fishshell.com/docs/current/index.html. Il est raisonnable de déduire que cette déclaration s'applique également aux variables exportées qui ne sont pas en casse spéciale, comme indiqué dans les sections "Tableaux" et "Variables spéciales" de ce même document.

J'ai le sentiment que fish ne devrait pas automatiquement segmenter les variables env dans une liste en dehors des variables spéciales délimitées par deux-points telles que PATH. Il devrait cependant y avoir un moyen robuste par lequel un utilisateur peut tokeniser un var dans un tableau sur un caractère arbitraire.

En l'absence d'un mécanisme de configuration du caractère à utiliser var par var (ala la commande zsh "typeset -T"), un espace doit être utilisé lors de la concaténation des éléments du tableau (encore une fois, en excluant les vars de cas spéciaux séparés par deux-points ). Évidemment, cela ne s'applique pas aux magasins de données privés tels que le stockage de variables universelles.

Enfin, je n'ai trouvé aucune utilisation dans les fonctions fish standard où un env var est utilisé pour passer un tableau contenant plus d'un élément à une autre fonction ou un autre script. De tels cas d'utilisation peuvent exister, mais cela devrait exiger que les scripts coopèrent explicitement à la sérialisation/désérialisation des données plutôt que de compter sur fish pour reconstruire implicitement des tableaux à partir de vars dont les chaînes contiennent le caractère séparateur d'enregistrement.

Merci pour votre réponse réfléchie. La section que vous avez citée à propos de la concaténation à l'aide d'un espace concerne spécifiquement les chaînes entre guillemets doubles. Nous devrions ajouter une discussion sur ce qui se passe avec les tableaux exportés.

Les utilisateurs peuvent tokeniser des chaînes avec par exemple set SOMEPATH (string split : $SOMEPATH) .

L'inconvénient des variables exportées concaténant l'espace est qu'elles sont modifiées lorsque fish est exécuté de manière récursive. Aujourd'hui cela fonctionne :

> set -x list 1 2 3
> count $list
3
> fish -c 'count $list'
3

Mais si nous exportions avec des espaces, cela afficherait 1 pour l'appel récursif. Comme vous le dites, nous ne comptons pas sur cela, mais c'est bien du point de vue de la cohérence.

Merci pour votre réponse réfléchie.

Je vais devoir le seconder ! Toujours agréable d'avoir un regard neuf sur les choses.

Pour ceux qui sont nouveaux dans cette discussion, je pense que je vais devoir apporter certaines des choses qui sont liées à cela.

Ce qui me vient immédiatement à l'esprit est la liste blanche listify , qui apparaît dans des problèmes comme # 2090.

Cela signifie que pour $PATH, $CDPATH et $MANPATH, ils apparaîtront sous forme de listes/tableaux à pêcher, mais lorsqu'ils seront exportés, ils seront à nouveau joints par ":". Ensuite, un poisson dans un poisson les divisera à nouveau. Cela fonctionne sur les deux-points, pas sur \x1e. D'après ma compréhension du code , il semble le faire sur chaque deux-points, sans aucune chance de s'échapper, donc il pourrait se casser sur les entrées $PATH avec un deux-points à l'intérieur - ce qu'UNIX autorise à l'intérieur des chemins de fichiers, bien qu'il semble cassé pour $PATH au moins . Ce schéma est également utilisé pour, par exemple, PYTHONPATH et GOPATH.

J'aimerais avoir quelque chose de légèrement plus explicite pour diviser les variables d'environnement que l'implicite always-split-on-\x1e-except-for-these-three-split-them-on-colon, car il s'agit en fait de deux schémas différents dans un et exporter une liste confondra toujours tout sauf le poisson.

Ma solution préférée serait une fonction comme splitenv var1 var2 var3 :

function splitenv --no-scope-shadowing
    set -e IFS # string split doesn't have superpowers, so unset IFS lest we split on both : and \n
    for arg in $argv
        set -q $arg; and set $arg (string split ":" $$arg)
    end
end

(Si string split avait des super pouvoirs , ce serait un peu plus simple)

Toutes les listes seraient alors jointes avec des deux-points lors de l'exportation, de sorte qu'un utilisateur peut les dissocier explicitement avec splitenv (bien que je ne sois pas mort sur une fonction d'assistance, je pense que rendre cela trivial est un bon chose à faire). Pour la rétrocompatibilité, splitenv PATH CDPATH MANPATH serait exécuté au démarrage. Si un utilisateur souhaite l'exporter différemment, string join est disponible.

Tout cela signifie que nous n'avons plus besoin de \x1e, nous avons un schéma qui a au moins une chance d'être compris par d'autres programmes, mais le poisson-dans-le-poisson (plutôt exotique à mon humble avis) devient maintenant fish -c 'splitenv list; count $list' .

Le problème est bien sûr que, comme mentionné, le schéma habituel de liste séparée par deux-points n'a aucun moyen d'échapper à un deux-points, et si nous voulions en ajouter un, string split n'a pas de "--non échappé" option pour diviser uniquement sur les séparateurs non échappés.

Est-ce que j'ai du sens ?

@faho Je pense que cette idée a du mérite. La pire partie de l'ancien schéma était implicitement le fractionnement sur les deux-points, ce qui altérait les variables qui ne devaient pas être fractionnées. Dans votre idée, c'est (presque) toujours explicite, donc je pense que c'est assez sûr.

En ce qui concerne l'échappement, ne pas échapper aux deux-points dans PATH est intentionnel selon le lien que vous avez trouvé. Je doute que PYTHONPATH, CLASSPATH, etc. soient plus cohérents à cet égard. Comme vous ne pouvez pas utiliser de deux-points dans ces chemins, nous pouvons choisir d'y échapper ou non ; mais si nous échappons à deux-points, nous devons échapper aux barres obliques inverses, et je parie que vous pouvez avoir une barre oblique inverse dans PATH. Nous aurons peut-être besoin d'une liste blanche "ne pas échapper" (pouah).

Alternativement, nous ne nous en soucions pas et laissons simplement n'importe quel deux-points agir comme délimiteur. Je pense que je penche vers cela pour la simplicité et la familiarité avec d'autres coquilles.

Nous sommes toujours confrontés au problème que certaines variables de type liste sont délimitées par des espaces et d'autres sont délimitées par deux-points. Une possibilité est que splitenv accepte un délimiteur, s'en souvienne et l'utilise pour reconstruire la valeur lors de l'exportation :

splitenv --on ' ' LESS
splitenv --on ':' PYTHONPATH

Ces appels jouent désormais le double rôle d'importer toute variable existante et de marquer la manière dont elle est exportée. Qu'est-ce que tu penses?

Existe-t-il également un moyen de le faire sans modifier config.fish ? Peut-être dans le cadre de variables universelles ?

Nous sommes toujours confrontés au problème que certaines variables de type liste sont délimitées par des espaces et d'autres sont délimitées par deux-points. Une possibilité est que splitenv accepte un délimiteur, s'en souvienne et l'utilise pour reconstruire la valeur lors de l'exportation :

Ça a l'air bien. Bien qu'à ce stade, faire de splitenv un script n'aiderait probablement pas, car nous aurions de toute façon besoin de la coopération du côté C++.

Ces appels jouent désormais le double rôle d'importer toute variable existante et de marquer la manière dont elle est exportée.

Il est possible que maintenant "splitenv" ne soit plus le nom parfait (c'était quand j'y ai pensé, bien sûr :rire: ) - j'ai aussi pensé à "listify".

Bien que cela me dérange que je ne puisse pas me rappeler où nous avons eu une discussion connexe auparavant - je pense que je devrai réexaminer les problèmes ce soir.

Les utilisateurs peuvent tokeniser des chaînes avec par exemple set SOMEPATH (string split : $SOMEPATH) .

La commande string n'est documentée nulle part que je puisse trouver. En outre, man string affiche la page de manuel string(3) qui documente les fonctions de manipulation de chaînes sur BSD (et Mac OS X).

Mais si nous exportions avec des espaces, cela afficherait 1 pour l'appel récursif. Comme vous le dites, nous ne comptons pas sur cela, mais c'est bien du point de vue de la cohérence.

Ce comportement est cependant surprenant. Je suis prêt à parier que si vous demandez à 100 personnes ce qui se passe lorsqu'un var avec plus d'un élément est exporté, 90 d'entre eux diront que les valeurs sont concaténées avec un espace comme séparateur. Quelques-uns pourraient dire qu'une virgule ou un autre caractère est utilisé comme séparateur. Et les deux personnes qui ont exécuté env diront que les valeurs sont concaténées sans séparateur car, à moins que vous ne filtriez la sortie par quelque chose comme cat -evt , le caractère séparateur d'enregistrement est invisible.

qui apparaît dans des numéros comme #2090

Je suis désolé mais je ne vois aucun mérite à la plainte de cet utilisateur. Le problème est trivialement contourné en testant explicitement si MANPATH est déjà défini. Ce qui, me semble-t-il, est quelque chose que vous devez faire dans tous les cas compte tenu de la sémantique des deux-points de début et de fin.

il peut donc se casser sur les entrées $ PATH avec deux-points à l'intérieur

Il est au moins trente ans trop tard pour y remédier. Nous ne devrions pas implémenter l'échappement des deux-points (et par extension le caractère d'échappement) car ce serait un comportement non standard. Jusqu'à récemment, j'ai passé plus de 20 ans en tant que spécialiste du support UNIX. Je n'ai jamais entendu quelqu'un se plaindre que la présence de deux-points dans un répertoire intégré dans $PATH ou une variable similaire était un problème.

Ma solution préférée serait une fonction comme splitenv var1 var2 var3

C'est bien, bien qu'il ne soit pas clair pourquoi le string split (non documenté) n'est pas suffisant. Que nous ayons besoin ou non d'une nouvelle fonction, nous ne devons absolument pas ajouter de nouvelles variables d'environnement auto-split. Les deux seuls qui sont suffisamment communs pour justifier ce comportement sont PATH et CDPATH (et MANPATH puisqu'il s'agit déjà d'un cas spécial). D'autres variables comme PYTHONPATH peuvent être explicitement divisées par un utilisateur s'il le juge utile.

Cependant, après avoir dit qu'il devrait certainement y avoir un moyen d'enregistrer qu'un var donné (par exemple, PYTHONPATH) devrait avoir ses éléments concaténés avec un caractère séparateur spécifique lors de l'exportation. La manière la plus naturelle de procéder consiste à utiliser une nouvelle option pour la commande set . Par exemple,

set -x -S ':' PYTHONPATH dir1 dir2 dir3

Cela n'affecterait pas la façon dont la var est stockée dans le magasin de données var universel où le caractère séparateur d'enregistrements serait toujours utilisé et il serait automatiquement divisé lors du chargement à partir de ce magasin de données. Il reste à déterminer si le caractère de séparation enregistré pour l'exportation doit également affecter l'interpolation de chaîne. Mon sentiment est qu'il devrait. C'est-à-dire que si la commande "set" ci-dessus est exécutée, une commande suivante

echo "PYTHONPATH is $PYTHONPATH"

devrait utiliser deux-points plutôt qu'un espace pour concaténer les valeurs de PYTHONPATH. Le séparateur par défaut est un espace pour préserver la sémantique existante et minimiser la surprise pour l'utilisateur. Notez que les vars à casse spéciale comme PATH utiliseraient également deux-points dans cet exemple. Ce qui est incompatible avec le comportement actuel mais cohérent avec la nouvelle sémantique et moins surprenant. En d'autres termes, pourquoi les éléments de $PATH sont-ils séparés par des deux-points dans l'environnement exporté mais par des espaces dans la sortie de

echo "PATH is $PATH"

La commande de chaîne n'est documentée nulle part que je puisse trouver. De plus, man string affiche la page de manuel string(3) qui documente les fonctions de manipulation de chaînes sur BSD (et Mac OS X).

Facile, tigre. C'est dans les versions de développement - voir https://github.com/fish-shell/fish-shell/blob/master/doc_src/string.txt

C'est bien, même si la raison pour laquelle la division de chaîne (non documentée) n'est pas suffisante n'est pas claire.

Mon idée de départ était qu'il s'agissait d'une fonction de commodité, donc cette opération devient complètement triviale. Avec la proposition de @ridiculousfish , cela devient quelque chose de plus et ajuste une sorte de magasin afin que la variable soit également jointe sur ce personnage lors de l'exportation. string split est juste une commande qui divise une chaîne - essentiellement notre version de cut .

La manière la plus naturelle de procéder consiste à utiliser une nouvelle option pour la commande set.

C'est une autre option, bien que je ne sois pas complètement convaincu par la sémantique. Par exemple set -S ':' PYTHONPATH . Cela définirait-il PYTHONPATH sur la liste vide ou diviserait-il simplement le PYTHONPATH existant? Jusqu'à présent, toutes les options définies ont fait la première, vous devez donc faire set -S ':' PYTHONPATH $PYTHONPATH . Ou nous ferions en sorte qu'il ne le fasse pas et qu'il y ait des incohérences dans le même outil.

En d'autres termes, pourquoi les éléments de $PATH sont-ils séparés par des deux-points dans l'environnement exporté mais par des espaces dans la sortie de echo "PATH is $PATH"

C'est en fait une bonne question. Bien sûr, vous ne vous attendriez pas à ce que le séparateur apparaisse dans, disons, for p in $PATH; echo $p; end , mais le joindre avec le séparateur par variable pourrait être la bonne chose à faire. Bien sûr, il y a string join pour le faire manuellement.

Ce comportement est cependant surprenant. Je suis prêt à parier que si vous demandez à 100 personnes ce qui se passe lorsqu'un var avec plus d'un élément est exporté, 90 d'entre eux diront que les valeurs sont concaténées avec un espace comme séparateur.

Il y a un problème général avec la conception par enquête et le poisson. Parce que les personnes interrogées auraient fréquemment connaissance de bash (et dans une moindre mesure d'autres shells POSIXy) alors que l'idée même de fish est de faire quelque chose de _mieux_ en abandonnant au moins une partie de POSIX.

Cela ne veut pas dire que c'est complètement sans valeur, c'est juste quelque chose à garder à l'esprit - si nous nous en tenions à ce genre d'idées, nous aurions le comportement de séparation des mots de bash et if-fi.

set -S ':' PYTHONPATH définirait-il PYTHONPATH sur la liste vide ou diviserait-il simplement le PYTHONPATH existant ?

Cela le définirait sur une liste vide. Si l'utilisateur souhaite conserver la valeur existante, il doit l'inclure explicitement (voir ci-dessous).

Nous avons déjà toutes les capacités nécessaires à l'exception d'un moyen de configurer le caractère (ou la chaîne vide) à utiliser lors de la concaténation des éléments de tableau d'une variable donnée pour l'exportation ou l'interpolation. Si quelqu'un veut manipuler un var comme PYTHONPATH, il peut soit le traiter comme une simple chaîne :

set PYTHONPATH "/a/new/dir:$PYTHONPATH"

Ou ils peuvent le traiter comme un tableau :

set -S ":" PYTHONPATH /a/new/dir (string split ":" $PYTHONPATH)

Notez que ma proposition d'utiliser le caractère de division/concaténation plutôt qu'un espace lors de l'interpolation dans une chaîne fournit un comportement cohérent, que l'utilisateur divise ou non la variable dans un tableau.

Je ne propose certainement pas une conception par comité. De cette façon se trouvent la folie et les bogosités comme zsh. Je signale simplement que lorsqu'on lui donne deux options ou plus sans autre raison de choisir l'une plutôt qu'une autre, choisir l'option qui surprendra le moins un utilisateur du shell est le meilleur choix. C'est aussi pourquoi je suis (pour le moment) opposé à l'introduction de nouvelles commandes ou comportements tels que les vars à fractionnement automatique (autres que PATH et CDPATH, bien sûr). C'est le genre de chose qui se fait rarement et généralement uniquement dans config.fish et quelques fonctions spécialisées comme le script "activate" d'Anaconda. Et la façon de faire en sorte que ce dernier se comporte correctement, que l'utilisateur ait ou non déjà divisé le var en un tableau dans son config.fish, est de toujours le traiter comme une chaîne qui doit être divisée. Par exemple, si PYTHONPATH devait être modifié, il pourrait faire quelque chose comme ceci :

# Hypothetical snippet from the Anaconda activate script.
if test (count PYTHONPATH) -gt 1
    set -S ':' PYTHONPATH /activated/python/tree $PYTHONPATH
else
    set PYTHONPATH "/activated/python/tree:$PYTHONPATH"
end

Ou, plus simplement,

# Hypothetical snippet from the Anaconda activate script.
set -S ':' PYTHONPATH /activated/python/tree (string split ':' $PYTHONPATH)

Oui, cela transforme potentiellement ce qui aurait pu être une simple chaîne en un tableau. Mais avec ma règle selon laquelle le caractère spécifié par le commutateur -S est utilisé lors de l'exportation et de l'interpolation de cette conversion dans un tableau, cela ne devrait pas avoir d'importance dans la pratique. Il y a cependant un cas particulier. Que se passe-t-il si l'utilisateur n'a pas explicitement converti le var en un tableau dans son config.fish et qu'il exécute ensuite quelque chose comme le script hypothétique ci-dessus. Le var devient potentiellement un tableau multi-éléments, ce qui signifie que s'ils le font par la suite

for elem in $PYTHONPATH
   echo $elem
end

Cela n'exécutera pas le corps de la boucle for une seule fois avec la valeur sous la forme de répertoires séparés par deux-points, comme l'utilisateur pourrait s'y attendre puisqu'il n'était pas au courant de la division effectuée par l'hypothétique script "activate". Je pense que nous pouvons vivre avec cela car il serait pervers pour un utilisateur de faire quelque chose comme ça.

tl;dr Je pense que les listes devraient "se souvenir" de leur délimiteur et voici pourquoi.


Je suis d'accord avec beaucoup de ce qui précède. Une chose qui semble encore fastidieuse est que les commandes ci-dessus semblent encore trop verbeuses; c'est-à-dire qu'il est parfois plus simple de décrire certaines de ces commandes en langage courant.

À titre d'exemple (et je ne me concentre pas autant sur la longueur que sur le nombre de choses répétées):

  • poisson : set -S ':' PYTHONPATH /activated/python/tree (string split ':' $PYTHONPATH)
  • Français : "ajouter /activated/python/tree à PYTHONPATH ( : -delimited`)"

Il y a deux choses répétées ici : PYTHONPATH et le délimiteur : . Que PYTHONPATH soit répété est sans doute acceptable pour deux raisons, et aucune de ces deux raisons ne s'applique au délimiteur.

  1. Il n'est pas difficile de deviner ce qui se passe quand quelqu'un dit set PYTHONPATH /activated/python/tree $PYTHONPATH , car cela ressemble beaucoup à des choses comme i = 2 + i , qui est un concept/idiome très familier. (Mais nous avons toujours des raccourcis comme += , c'est pourquoi je propose le drapeau --append ci-dessous.) D'un autre côté, quand les gens pensent à ajouter à une liste, ils ne pensent pas à diviser et se joindre sur un délimiteur. Ils ne pensent pas à convertir la liste entière dans un autre format, à y faire la véritable opération et à la remettre en place. Dans leur esprit, ils lisent naturellement le délimiteur comme un délimiteur au lieu de le changer en un délimiteur "interne" ou "préféré".
  2. L'utilisation d'une simple commande set pour l'ajout évite l'ajout d'une autre commande pour joindre deux listes différentes. D'un autre côté, la conversion d'un délimiteur à un autre est quelque chose que nous ne voulons idéalement jamais que l'utilisateur fasse manuellement, principalement pour la raison ci-dessus.

En revanche, je propose une autre façon de spécifier le délimiteur sur les listes : l'associer indéfiniment à la liste. Ainsi, l'exemple ci-dessus peut être fait comme suit :

# Changes the delimiter for this list. This might be done in some global config file for common lists as this one.
set -S ':' --no-modify PYTHONPATH
# or, workaround if you don't want to add extra options to set:
set -S ':' PYTHONPATH $PYTHONPATH

# The actual append operation
set --prepend PYTHONPATH /activated/python/tree
# or, workaround if you don't want to add extra options to set:
set PYTHONPATH /activated/python/tree $PYTHONPATH

Implications/questions de suivi/etc :

  1. Ceci est assez compatible avec la suggestion actuelle. Voici les modifications requises :

    • Faites coller le délimiteur (éventuellement en utilisant une autre variable comme __fish_sep_PYTHONPATH )

    • (optionnel) Ajoutez un drapeau que j'appelle actuellement --no-modify , qui dit à fish de changer le délimiteur d'une liste sans changer son contenu. Ajoutez éventuellement également les drapeaux --append et --prepend pour la raison (1) ci-dessus. Quoi qu'il en soit, celui-ci n'est pas nécessaire, comme le montre la solution de contournement ci-dessus, à la façon dont l'ajout et la préfixation sont effectués dans les poissons aujourd'hui.

  2. Dans le poisson, les listes doivent au moins _être traitées_ comme des citoyens de première classe. Cela signifie que la modification du délimiteur doit modifier la représentation sous forme de chaîne, et non la représentation sous forme de liste (sauf si le délimiteur est présent dans l'un des éléments, auquel cas le fractionnement est inévitable). Par exemple, si vous changez les délimiteurs de , à : , ["0:1", "2"] devrait devenir ["0", "1", "2"] et non ["0", "1,2"] (ce qui est ce que se produirait si vous changez simplement le délimiteur sans changer la chaîne de sauvegarde de la liste). Ce comportement doit maximiser la compatibilité avec le comportement actuel et le fait qu'il existe actuellement un délimiteur immuable par défaut.

Voici la ligne du bas :

  • Cela implique beaucoup moins de jetons et presque rien ne se répète.
  • Cela correspond au modèle mental de nombreux utilisateurs. Les utilisateurs pensent en ces termes : "préfixer", "définir le délimiteur", "ne pas modifier".
  • Cela semble être la seule bonne façon de faire cette tâche (l'ancienne méthode semble maintenant très maladroite), et donc ces ajouts ne détruisent pas l'orthogonalité.
set --no-modify -S : PYTHONPATH
set --prepend PYTHONPATH /activated/python/tree

Merci, @szhu , pour le commentaire détaillé concernant ma proposition. Cependant, la solution que vous proposez pose de nombreux problèmes. Par exemple, l'ajout de l'option --no-modify modifie en fait la variable en la convertissant en liste et donc modifie la variable. Bien que je rejette presque tous les éléments de votre proposition, cela m'a fait réfléchir à une solution plus simple qui répondrait à la plupart, sinon à la totalité, de vos points. Peut-être devrait-il y avoir un mécanisme pour dire à fish qu'une variable d'environnement donnée doit toujours être automatiquement divisée et reconstituée sur un jeton donné (par exemple, ":" ou " "). Cela pourrait être appelé une désignation de tableau automatique et lors de son exécution, toute valeur existante serait immédiatement divisée si elle n'était pas déjà un tableau.

Une nouvelle option pourrait être ajoutée à la commande set pour activer ce comportement. Cependant, je crains que cela soit ambigu et puisse être interprété comme définissant une variable sans valeur. L'ajout d'une option -A token à la commande set serait-il sans ambiguïté ? Par exemple:

set -x -A ':' PYTHONPATH

Vraisemblablement, cela convertirait immédiatement toute variable d'environnement PYTHONPATH existante en un tableau après avoir été divisée sur deux-points. Cela entraînerait à l'inverse la concaténation des valeurs sur deux-points lors de l'exportation ou de l'interpolation dans une chaîne. De même, même si PYTHONPATH n'existait pas au moment où cette commande a été exécutée, la spécification de tableau automatique serait mémorisée et les utilisations ultérieures seraient affectées. Par exemple, cela créerait évidemment un tableau :

set PYTHONPATH /a/path /b/path /c:/d/path

Mais qu'en est-il de ce dernier argument ? Doit-il être automatiquement divisé en deux jetons ?

Notez que ce comportement ne devrait s'appliquer qu'aux variables exportées et qu'une erreur serait générée dans le cas contraire. Il y a aussi quelques cas particuliers qui doivent être précisés. Par exemple, que se passe-t-il si la déclaration de fractionnement automatique d'origine inclut des valeurs comme dans cet exemple :

set -x -A ':' PYTHONPATH 'hello:goodbye' $PYTHONPATH

Ces valeurs doivent-elles être divisées sur le jeton de fractionnement automatique ? Ou cela devrait-il entraîner une erreur et nécessiter la modification de la valeur dans une instruction distincte ? Et quelle que soit la syntaxe choisie, vous avez toujours la question de savoir quoi faire des valeurs qui contiennent le jeton de fractionnement automatique. Le diable est dans les détails. C'est-à-dire qu'il peut y avoir d'autres ramifications de cette proposition auxquelles je n'ai pas pensé. Ma proposition originale avec une syntaxe plus détaillée évite ces problèmes pour autant que je sache.

@krader1961 , merci pour votre réponse. Cependant, vous semblez penser que je convertis des variables de chaînes en listes. Je pense que vous comprenez mal un concept important dans fish : chaque variable est une liste de chaînes . Les variables qui semblent être des chaînes sont en fait des listes de longueur 1. fish ne les traite pas différemment des listes de longueur 0 ou 2 ou de toute autre longueur.

Notez également que même si la chaîne sous-jacente utilisée pour transmettre les variables d'environnement peut changer lorsque vous modifiez les délimiteurs, l'une des caractéristiques de fish est que l'utilisateur n'a généralement pas besoin de penser aux délimiteurs. C'est pourquoi je recommande que l'option -S ne fasse que spécifier comment cette liste doit être convertie en chaîne lorsqu'elle est _exportée en dehors_ du poisson. -S ne doit pas modifier la représentation de la liste des poissons (sauf dans les cas où il est impossible de représenter cette liste à l'aide du délimiteur cible).

Au fait, voici un exemple qui montre à quel point ma proposition est propre. Voici le code pour reconvertir une variable $L vers le délimiteur par défaut de \x1e . Cela n'aura absolument aucun effet sur les variables (n'importe quelle portée, n'importe quel nombre d'éléments) qui peuvent être créées dans fish aujourd'hui.

set -S \x1e L $L

Encore une chose : la famille d'arguments --no-modify ne sont que des raccourcis. Voici leurs équivalents :

| raccourci | équivalent |
| --- | --- |
| set [other args] --no-modify L | set [other args] L $L |
| set [other args] --prepend L $TOADD... | set [other args] L $TOADD... $L |
| set [other args] --append L $TOADD... | set [other args] L $L $TOADD... |

(J'ai déjà dit ce qui suit, mais je pense que je peux mieux l'expliquer maintenant.) En soulignant à quel point ces trois arguments sont "stupides", certains peuvent se demander s'ils sont vraiment nécessaires. On peut citer que le poisson a un principe de conception d'orthogonalité . Lorsque toutes les choses sont orthogonales, cela signifie que pour toute tâche importante que vous souhaitez effectuer, il devrait être évident quel ensemble de fonctionnalités choisir pour effectuer cette tâche - il ne devrait y avoir qu'une seule bonne façon de le faire. Ici, j'ajoute en effet une autre façon d'ajouter/d'ajouter/d'empêcher la modification d'une liste, mais c'est uniquement parce que je pense que les équivalents remplacés sont inutilement verbeux ; ils ne devraient pas être les bons moyens d'ajouter des listes de modifications. Une façon de vous en convaincre est de réfléchir à la façon dont vous envisagez d'ajouter à une liste. Vous pensez probablement "ajouter $TOADD à $L " plutôt que "mettre $L à $L $TOADD ".

Faites-moi savoir ce que vous pensez, et si cela rend un cas plus convaincant pour ma proposition. (De plus, il est assez courant pour moi de mal comprendre les choses, alors n'hésitez pas à me corriger.)

@szhu Je suis tout à fait conscient que tous les vars dans les poissons sont des listes de zéro, une ou plusieurs valeurs. Vous n'avez apparemment pas non plus lu mes commentaires précédents dans lesquels j'indique clairement que le délimiteur associé ne doit pas affecter la représentation interne ou la manière dont les valeurs sont conservées dans le magasin de données universel (autre que le stockage du délimiteur). Vous n'avez pas non plus abordé mes points précédents. Considérez votre dernier exemple :

set -S \x1e L $L

Que devrait-il faire si L contient déjà deux valeurs ou plus ? Vraisemblablement rien d'autre que de changer le délimiteur associé. L'argument $L serait-il facultatif dans ce cas ? Ou doit-il d'abord convertir le tableau existant en une simple chaîne (en concaténant vraisemblablement à l'aide du délimiteur existant), puis diviser cette chaîne sur le nouveau délimiteur ? Comme je l'ai déjà dit, le diable est dans les détails.

En fin de compte, les concepteurs et les mainteneurs établis décideront si votre famille de fonctions --no-modify doit être ajoutée ou non, mais je vote non car elles n'ajoutent pas assez de valeur à mon avis par rapport à leur coût.

Désolé, ce fil est long, j'ai dû manquer votre reconnaissance de cela ci-dessus; bon à savoir que nous sommes sur la même page! Je pense avoir également répondu à la plupart de vos préoccupations ci-dessus, mais pas à toutes. Je répondrai spécifiquement à chacune de vos préoccupations ci-dessous.


1. Le $L est-il facultatif dans set -S \x1e L $L ?

Le comportement existant de set ne changera pas. Sous le comportement actuel, set L $L ne change pas L et set L fait L une liste vide. Idem avec set -S \x1e L $L et set -S \x1e L .

1.1 set -S \x1e L $L ne semble-t-il pas trop verbeux pour avoir simplement changé le délimiteur ?

Légèrement. C'est pourquoi je propose l'option --no-modify comme raccourci pour cela.

Mais mon plan ne s'effondrera pas si ce raccourci n'existe pas. Nous traitons déjà ce problème tous les jours lorsque nous ajoutons des listes : set PATH ~/.bin $PATH . C'est pourquoi, pour la même raison, je propose également --prepend et --append .

2. Comment se déroulerait le processus de conversion ?

Disons que notre ancien délimiteur est \x1e et que le nouveau est : , et que nous avons une liste de poissons ["hello", "world"] (exportée en hello\x1eworld ). Il existe deux méthodes de base pour effectuer la conversion (" options de conversion ") :

  1. Utilisez ["hello", "world"] et convertissez-le en ["hello", "world"] (exporté en hello,world )
    Avantage : La représentation de la liste ne change pas.
  2. Utilisez hello\x1eworld et convertissez-le en ["hello\x1eworld"] (exporté en hello\x1eworld )
    Avantage : La représentation de la valeur exportée ne change pas.

Notez qu'il s'agit d'une perspective d'interface utilisateur et non d'une perspective d'implémentation ; nous parlons de ce à quoi il ressemble pour l'utilisateur. Je couvrirai la mise en œuvre dans la prochaine question. _Remarque : le reste de cette réponse est un élément nouveau que je n'ai pas abordé ci-dessus, à la suite de vos questions. Merci!_

Au sein du poisson. Premièrement, si nous travaillons entièrement sur les poissons, les listes sont de première classe et vous ne devriez jamais avoir à vous soucier des délimiteurs, et donc aucun n'est requis. (Encore une fois, "devrait" est du point de vue de l'utilisateur, en tant que développeurs, il est de notre responsabilité de rendre cela vrai.)

Modification du format d'exportation de vars. Ainsi, la seule raison pour laquelle un utilisateur devra changer les délimiteurs est de changer la chaîne exportée pour les programmes qui lisent les variables d'environnement. Pour les listes créées dans fish, nous utiliserons certainement l' option de conversion 1 , car la signification de la variable en tant que liste est importante et bien définie, nous devons donc préserver la représentation de la liste.

Modification du format d'importation de vars. Cependant, pour les variables d'environnement comme PATH qui sont initialement créées en dehors de fish, nous devons, pour une liste qui a déjà un délimiteur, dire à fish quel est ce délimiteur. Pour cela, nous pouvons utiliser l' option de conversion 2 .

2.1 Comment cela serait-il mis en œuvre ?

Fish même si l'utilisateur n'a pas besoin de le savoir, fish stocke en fait des listes sous forme de chaînes. La variable x est stockée sous la forme hello\x1eworld . Selon ma proposition, il y aurait une autre variable, __fish_delimiter_x , qui spécifie le délimiteur de la variable x . Il n'existe pas actuellement et nous utilisons donc le délimiteur par défaut, \x1e .

Pour l'option de conversion 1 :

  1. Divisez la variable sur l'ancien délimiteur, ce qui donne une vraie liste dans le langage d'implémentation (C++).
  2. Joignez-vous à la liste à l'aide du nouveau délimiteur, ce qui donne une nouvelle chaîne.
  3. Enregistrez le nouveau délimiteur dans __fish_delimiter_x .

Pour l'option de conversion 1, une implémentation équivalente :

  1. Dans la variable, remplacez toutes les occurrences de l'ancien délimiteur par le nouveau.
  2. Enregistrez le nouveau délimiteur dans __fish_delimiter_x .

Pour l'option de conversion 2 :

  1. Enregistrez le nouveau délimiteur dans __fish_delimiter_x .

2.2 Si nous avons besoin des deux options de conversion, comment l'utilisateur spécifierait-il laquelle utiliser ?

Nous pouvons peut-être avoir deux options : -D ou --convert-delimiter pour l'option 1 et -d ou --set-delimiter pour l'option 2.

2.3 Avons-nous vraiment besoin des deux options ?

Sous le poisson actuel, nous choisissons de supposer que nous ne verrons pas \x1e dans la nature en dehors du poisson. Si nous gardons cela comme délimiteur par défaut et conservons cette hypothèse, l' option de conversion 1 est suffisante pour convertir et définir le délimiteur et nous n'aurons pas besoin de l'option de conversion 2 . (Un moyen simple de s'en convaincre est de se rendre compte que si l'hypothèse est vraie, lors de la conversion de listes créées en externe, l'étape de l'option de conversion 1 "remplacer toutes les occurrences de l'ancien délimiteur par le nouveau" ne fera rien, réduisant l'ensemble de la conversion à l'option de conversion 2.)


@ridiculousfish , j'apprécierais également vos commentaires à ce sujet, en particulier en ce qui concerne l'interface utilisateur et les détails de mise en œuvre. Merci!

Il semble qu'il y ait deux problèmes ici. Parlons juste du premier ?

+1 pour le vrai tableau

Cette astuce de séparation est-elle vraiment nécessaire pour les poissons ? Ping #627

Revisiter cela à la lumière de mon correctif pour le problème # 2106 dans lequel j'ai remarqué qu'il y avait deux façons incompatibles de convertir la représentation sous forme de chaîne pour les valeurs variables en tableaux. L'un d'entre eux a élidé de manière incorrecte les éléments vides. Le problème principal est que class env_var_t est basé sur wcstring plutôt que sur un vecteur de wcstring. La question de savoir si cela en vaut la peine ou non est sujette à débat.

Si vous suivez ce numéro, je vous encourage à jeter un coup d'œil et peut-être à tester le PR #4082. J'ai décidé que la meilleure façon de résoudre ce problème consiste à utiliser des variables "liées" similaires à la fonctionnalité du même nom dans zsh.

Il semble que les questions entourant ces listes exportées par les deux-points et quels envvars devraient être inclus dans cette liste blanche soient encore indécises. Quel est l'état actuel de ce dossier ? Peut-on espérer une solution définitive à ce sujet ? Juste aujourd'hui, je tombe à nouveau dans le piège que LD_LIBRARY_PATH n'est pas dans la liste blanche...

Pour résumer : les variables d'environnement Unix sont des chaînes, donc les variables d'environnement de type tableau doivent utiliser un délimiteur. La plupart utilisent des deux-points ($PATH); bien que tous ne le fassent pas (MOINS DE $). Nous aimerions simplement utiliser des deux-points pour délimiter tous les tableaux lors de l'importation/exportation (et en effet, les poissons fonctionnaient de cette façon) ; le problème est que certaines variables plates contiennent des deux-points ($DISPLAY, $SSH_CONNECTION).

L'objectif est de faire en sorte que les variables délimitées fonctionnent naturellement avec le support des tableaux de fish. @szhu a suggéré d'améliorer set pour suivre un délimiteur, mais l'amélioration de l'OMI set n'est pas le bon endroit pour attacher ceci :

  • Interaction ennuyeuse entre la définition de la variable et la définition de son délimiteur (motivant --no-modify ).
  • Questions délicates sur la façon dont les délimiteurs interagissent avec la portée variable.
  • Problèmes autour des variables universelles. Nous devrions apprendre aux uvars à se souvenir du délimiteur, et aussi environ --no-modify car il n'y a aucun moyen de définir une variable à sa valeur actuelle avec les uvars.

À l'examen, je suis favorable à l'idée de splitenv de @faho . splitenv name diviserait la variable existante sur les deux-points, c'est tout. C'est merveilleusement simple. Les variables qui n'utilisent pas les deux-points sont suffisamment rares pour que nous n'ayons pas besoin d'un support spécial pour elles.

L'inconvénient est que les tableaux exportés par les poissons seraient réimportés sous la forme d'une chaîne délimitée par deux-points ; dans la pratique, je pense que ce sera rare.

Nous ne devrions pas infliger cette complication splitenv aux utilisateurs si nous pouvons l'éviter. Je veux donc aller plus loin et étendre la liste blanche des deux-points à toutes les variables d'environnement dont le nom se termine par PATH , par exemple LD_LIBRARY_PATH, PYTHONPATH, etc. En pratique, cela devrait faire la bonne chose presque tout le temps ; toute personne mordue peut utiliser string join pour corriger la valeur.

Donc ce que je propose (vraiment la proposition de faho):

  • Exportez tous les tableaux en utilisant les deux points ; plus de séparateur d'enregistrements ASCII.
  • Implémentez une fonction splitenv qui divise une variable en deux-points. Cela peut être écrit en écriture de poisson.
  • Améliorez la liste blanche séparée par deux-points pour toutes les variables se terminant par PATH.

Je pense que cela résoudra la plupart des problèmes associés aux tableaux délimités par des deux-points d'une manière minimaliste et compatible.

concernant l'idée splitenv:

Disons que je voulais que fish exporte une liste dont les éléments contiennent des deux-points, par exemple : ["item1", "item:2"] . (Je ne pense pas que ce soit un événement rare, en particulier lorsque des tableaux sont utilisés pour stocker les entrées de l'utilisateur.)

La liste sera-t-elle exportée au format item1:item:2 ? Si tel est le cas, il sera impossible de recréer la liste d'origine après l'exportation.

De plus, avoir une liste blanche immuable pour les variables semble mal, bien que la liste blanche soit *?PATH semble moins mal. (C'était une autre raison de ma proposition de stocker le délimiteur en tant que variable - la liste blanche peut être modifiée en définissant une variable.)

@szhu Vous avez raison. Exported-lists-can't-contain-colons est un problème dont souffre déjà Unix :

Depuis \

donc je ne me sens pas trop mal d'introduire la même limitation pour les poissons (uniquement pour les variables exportées).

De plus, ce problème ne se produit que lors de l'exportation d'un tableau vers une instance de poisson invoquée de manière récursive, ce qui, je pense, sera rare. Si cela s'avère courant, nous pourrions soit attacher des données sidecar dans une autre variable, soit utiliser un séparateur de tableau différent lors de l'appel récursif de fish. Je suppose que nous n'aurons pas besoin d'aller aussi loin.

Je conviens que le cas limite où la proposition ne fonctionne pas bien n'est pas très courant, mais je crains que ce ne soit vraiment mauvais si les gens s'y heurtent.

Voici un exemple qui n'est que partiellement artificiel :

set -x TEST color:red 
set -x TEST2 color:red font:serif
set -x TEST_PATH color:red 
set -x TEST2_PATH color:red font:serif
exec fish
echo $TEST #=> color:red
echo $TEST2 #=> color:red:font:serif
echo $TEST_PATH #=> color red 
echo $TEST2_PATH #=> color red font serif

Je peux imaginer que beaucoup de nouveaux utilisateurs soient confus après avoir observé ce qui précède.

Je pense que le comportement suivant serait nettement plus agréable :

set -x TEST color:red 
set -x TEST2 color:red font:serif
set -x TEST_PATH color:red 
set -x TEST2_PATH color:red font:serif
exec fish
echo $TEST # color:red
echo $TEST2 # color:red font:serif
echo $TEST_PATH #=> color:red 
echo $TEST2_PATH #=> color:red font:serif

J'aimerais avoir votre avis et celui de la communauté à ce sujet.

Pourquoi ne pas échapper aux colons existants ? Cela préserverait la distinction.

S'évader a du sens pour moi.

Pourrait-il encore être déroutant de ne pas se souvenir si une variable est un tableau?

set -x TEST2 color:red font:serif
set -x TEST2_PATH color:red font:serif
exec fish
echo $TEST2 # color\:red:font\:serif
echo $TEST2_PATH #=> color:red font:serif

Oui. Mon hypothèse est que l'exportation de tableaux n'est pas courante, en dehors des listes de chemins.

MANPATH a une signification particulière pour les doubles-points (::) - voir #2090 - est-ce que cela jette une clé dans les travaux ?

Je dirais également qu'avoir une variable sidecar FISH_ARRAY_VARIABLES=FOO\t:\nBAR\t;\nBAZ\t-\n dans tous les cas serait un bon indice pour les instances où Fish est invoqué pour récupérer à nouveau les variables du tableau, sans perturber les autres processus et sans nécessiter un "nous sommes involing fish now" checker..

re : https://github.com/fish-shell/fish-shell/issues/436#issuecomment -392409659 @zanchey
Je n'ai pas lu # 2090 en détail, mais je pense que la conversion entre les formes de chaîne délimitée par deux-points et de tableau est complètement transparente (sauf lorsque les deux-points ~ n'apparaissent pas ~ apparaissent dans les éléments du tableau).

Pour inclure un double-virgule dans MANPATH , ajoutez simplement une chaîne vide où le double-virgule doit apparaître :

$ set -x MANPATH 1 2 '' 3
# Check if it's set
$ bash -c 'echo $MANPATH'
1:2::3

Pour commencer MANPATH par deux-points, ajoutez simplement un élément de chaîne vide au début :

$ set -x MANPATH '' 1 2 3
# Check if it's set
$ bash -c 'echo $MANPATH'
:1:2:3

Je n'ai pas tout suivi ici, mais en tant qu'utilisateur, je veux plaider pour "aucune configuration".
Je pense que set -S et splitenv sont des formes de configuration. Certains utilisateurs les feraient dans fish.config et géreraient PYTHONPATH comme un tableau. D'autres ne le feraient pas et traiteraient PYTHONPATH comme un seul mot délimité par deux-points. Copier-coller les conseils de stackoverflow et exécuter des scripts manipulant PYTHONPATH d'un utilisateur à un autre ne fonctionnerait alors pas toujours...

Une règle fixe "si elle se termine par PATH " est sans configuration et semble aussi parfaite que possible :+1 :
(Je n'ai pas d'opinion sur la valeur de l'incompatibilité ascendante)
Oui, set -x TEST2_PATH color:red font:serif serait importé en tant que tableau color red font serif mais c'est le problème avec l'exportation de variables. Vous ne pouvez pas vraiment définir une variable exportée dans un tableau sans comprendre comment cela fonctionne.

Oui. Mon hypothèse est que l'exportation de tableaux n'est pas courante, en dehors des listes de chemins.

@ridiculousfish cela peut être vrai dans les coquilles actuelles, mais j'imagine qu'à mesure que le poisson gagne en traction, les utilisateurs pourraient vouloir tirer parti de la capacité du poisson à envoyer des listes aux coquilles de poisson enfant. Je peux imaginer qu'il peut éventuellement y avoir des programmes/plugins qui gèrent l'état d'une session fish (je revérifierai ce commentaire dans quelques années pour voir si cela est vrai), et être capable de dés/sérialiser universellement des listes rendra ce code plus propre et moins de contournement.


Une sorte de pensée similaire mais légèrement différente : traiter PATH comme un cas particulier est un cas marginal anachronique que les utilisateurs ne comprennent probablement que s'ils ont un historique des cas d'utilisation typiques des shells. Cela limite la capacité de fish à être utilisé comme langage de script général et limite certains cas d'utilisation futurs potentiels.

@ridiculousfish Je pense qu'une solution possible consiste à associer chaque variable d'environnement/tableau à son propre séparateur (et vous pouvez conserver '\x1e' ou ' ' ou ':' par défaut), et l'utilisateur qui crée la variable d'environnement est responsable du choix des séparateurs appropriés pour éviter les conflits. La commande peut ressembler à : set --separator ':' TMP 1 2 3 . Ainsi, pour ces variables d'environnement bien connues, les utilisateurs peuvent simplement choisir les séparateurs bien connus correspondants qui peuvent également être reconnus par d'autres programmes et peuvent rendre fish plus compatible avec plus de programmes (tels que Python).

Pour ceux qui ne lisent que des commentaires récents, notez simplement que la recommandation set --separator @thuzhf est la même que la recommandation set -S mentionnée à plusieurs reprises tout au long de ce fil. Pour obtenir plus de contexte sur cette discussion, vous pouvez grep cette page pour set -S .

@szhu Désolé de ne pas avoir remarqué le précédent set -S . C'est en gros ce que je veux aussi. J'ai également remarqué qu'il y avait plusieurs préoccupations que d'autres avaient sur cette nouvelle option. Je peux donner mon avis sur ces préoccupations ci-dessous (puisque l' ensemble de poissons n'a pas utilisé -s comme option, j'utiliserai -s pour faire référence à --separator ci-après):

  1. --no-modify modifie quelque chose. Oui, et vous devez modifier le nom pour qu'il soit explicite, par exemple, --change-separator .
  2. Il y a quelques cas délicats. Ceci est essentiellement dû à la syntaxe mal définie et peut être évité naturellement si nous donnons une définition stricte de la syntaxe. Par exemple:

    1. Idée de base : chaque var (liste) est associée à son propre séparateur lorsqu'elle est définie (la valeur par défaut est ' ' ). Ce séparateur sera utilisé lorsque cette variable est créée à partir d'une chaîne et lorsqu'elle est convertie en chaîne (c'est une idée courante dans certains langages tels que la fonction join() de Python). Une variable est convertie en chaîne lorsqu'elle est exportée ou lorsque l'utilisateur souhaite le faire.

    2. Comment créer des variables d'environnement



      1. set ENV_VAR a b c . Sans -s , nous choisissons ' ' comme séparateur par défaut.


      2. set -s ':' ENV_VAR . Dans ce cas, ENV_VAR est défini comme une liste vide.


      3. set -s ':' ENV_VAR a b:c d e:f . Dans ce cas, les utilisateurs qui écrivent ce code doivent clairement comprendre ':' est le séparateur et comprendre que ENV_VAR sera un tableau comme ['a b', 'c d e', 'f'] et sera exporté comme 'a b:c d e:f' . Et si vous voulez que l'ENV_VAR exporté commence par des espaces et se termine par des espaces ? Vous devez utiliser des échappements tels que : set -s ':' ENV_VAR \ a b:c d e:f\ . Alors ENV_VAR sera [' a b', 'c d e', 'f '] et sera exporté comme ' a b:c d e:f ' .


      4. set -s ':' ENV_VAR a b:c d e:f $ENV_VAR . Dans ce cas, cela dépend du fonctionnement $ . Si elle est définie comme extrayant la valeur de chaîne de ENV_VAR au lieu de la liste, alors cette commande sera la même que simplement remplacer $ENV_VAR par sa valeur de chaîne convertie à partir de la liste ci-dessous, et dans ce cas, set -s ':' ENV_VAR a b:c d e:f:$ENV_VAR est probablement ce que vous voulez vraiment (remarquez le : après f ); si elle est définie comme extrayant la variable de ENV_VAR (qui est une liste au lieu d'une chaîne), alors cela devrait devenir une opération d' extension de liste comme en python. Par exemple, dans ce dernier cas, si ENV_VAR est ['x', 'y'] avant, alors après cette opération ENV_VAR deviendra ['a b', 'c d e', 'f', 'x', 'y'] . Que faire si le séparateur précédent ENV_VAR n'est pas ':' ? Dans le premier cas, il est de votre responsabilité de vous assurer que vous faites la bonne chose, par exemple, vous devriez probablement utiliser un séparateur cohérent en changeant le séparateur d'origine en ':' ou en changeant le séparateur actuel pour qu'il soit celui d'origine. Dans ce dernier cas, cela définira le séparateur de ce tableau par rapport à celui d'origine (quel qu'il soit) à ':' .



    3. Comment changer de séparateur



      1. set --change-separator ':' ENV_VAR . Si ENV_VAR n'existe pas, le programme doit se terminer avec un code d'erreur autre que 0. Simple et assez explicite.



    4. Comment afficher le séparateur



      1. set --view-separator ENV_VAR .



En outre, je pense vraiment que ce problème est évident et urgent et constitue un gros problème pour les utilisateurs et j'espère que ce problème pourra être résolu dès que possible, car cela affecte considérablement l'expérience utilisateur. En fait, je n'ai pas rencontré d'autres problèmes (même très petits) pour l'instant en utilisant du poisson, sauf celui-ci, si gros.

Je pense vraiment que ce problème est évident et urgent

@thuzhf : Je dirais que vous surestimez cela.

L'une des raisons étant que votre problème dans #5169 était avec $LD_LIBRARY_PATH, mais ce n'est pas vraiment une liste de poissons ! Vous devez le définir comme set LD_LIBRARY_PATH "$LD_LIBRARY_PATH:/some/path" , comme dans les autres shells.

Fish transforme automatiquement trois variables héritées/exportées en listes :

$PATH, $MANPATH et $CDPATH. Et exactement cette liste aura un séparateur ":" lors de l'exportation.

D'autres variables "standardisées" comme $LD_LIBRARY_PATH ne doivent pas être traitées comme des listes dans fishscript, vous n'avez donc pas ce problème. Les variables qui ne sont pas standardisées, vous pouvez les gérer comme bon vous semble, puisque les autres programmes ne feront rien avec elles de toute façon, donc le séparateur n'est pas critique.

@faho Merci pour votre explication claire. Cela a vraiment beaucoup de sens pour moi. OK, je peux dire que ce problème est résolu pour moi.

J'ai jeté un coup d'œil au problème MANPATH décrit dans #2090. Le scénario consiste à ajouter à manpath de sorte qu'il continue à utiliser les chemins système.

En bash, on écrirait ceci comme export MANPATH="$MANPATH:/new/path" . Si MANPATH est défini, cela s'y ajoutera. S'il n'est pas défini, cela ajoutera deux-points, qui est une indication spécifique à l'homme pour utiliser les répertoires système. Cette syntaxe ne fonctionne pas dans fish ; le problème est que MANPATH est un tableau et donc "$MANPATH" aura des espaces au lieu de deux-points.

Une approche "variables liées" nous permettrait d'avoir par exemple fish_manpath comme un tableau qui reflète MANPATH comme une chaîne séparée par deux-points. Cela pourrait être construit entièrement en script de poisson. Cependant, nous voudrions le faire pour toutes les variables de type chemin, pas seulement MANPATH, et ce serait une rupture de compatibilité importante qu'il n'est pas clair de savoir comment gérer. De plus, il a les mêmes problèmes, par exemple la variable de tableau manpath dans zsh est difficile à ajouter, donc on ne sait pas pourquoi elle existe même.

Ma proposition ici ne rend pas la situation MANPATH meilleure ou pire; Je pense que la chose à faire est de lancer et d'avoir juste une histoire facile à ajouter à MANPATH, qui est la suivante :

set -q MANPATH || set MANPATH ''
set -x MANPATH $MANPATH /new/path

Ce n'est pas trop pénible à coller dans config.fish.

Ma proposition ici ne rend pas la situation MANPATH meilleure ou pire; Je pense que la chose à faire est de lancer et d'avoir juste une histoire facile à ajouter à MANPATH, qui est la suivante :

@ridiculousfish : J'ai pensé à aller plus loin, en fait : divisez ces variables spéciales sur " : " également en affectation, et joignez-les avec " : " au lieu de l'espace dans l'expansion entre guillemets.

Cela signifie que lorsque vous faites set -gx MANPATH "$MANPATH:/new/path" , fish va et effectue automatiquement le fractionnement, ce qui donne l'équivalent de set -gx MANPATH "" /new/path .

Maintenant, cela signifie que ":" ne peut pas apparaître dans un chemin dans $MANPATH (et $PATH, et $CDPATH), mais ils ne peuvent pas le faire de toute façon car cela casserait les utilitaires non-fish !

Cela nous permettrait également peut-être un jour de supprimer la gestion spéciale, car cela ajoute une manière compatible de la gérer - il vous suffirait de l'affecter avec le : et de l'utiliser avec (string split : -- $MANPATH) , et cela fonctionnerait même si cette gestion était supprimée.

@faho Je me réchauffe à l'idée - comment l'utilisateur marquerait-il une variable comme recevant ce traitement spécial? Est-ce que splitenv le ferait ?

comment l'utilisateur marquerait-il une variable comme recevant ce traitement spécial ?

Mon idée était en fait de ne pas autoriser le marquage du tout - laissez-le simplement comme comportement spécial pour $PATH et al. Ce qui nous permettrait d'éviter de lister à un moment donné dans le futur.

Cependant, j'ai depuis compris que permettre cela pour d'autres variables nous aide également avec d'autres variables - par exemple, j'ai déjà dit que mon $EDITOR est défini comme un élément ( set EDITOR "emacs -nw" ) pour la compatibilité avec externe outils, mais les poissons préféreraient que ce soit une liste.

Donc, je choisirais probablement par défaut _space_ comme délimiteur, à moins qu'il ne s'agisse d'un PATH (et en supposant que c'est le cas si le nom se termine par PATH, c'est probablement correct).

Est-ce que splitenv le ferait?

Je n'aime pas vraiment introduire une autre fonction intégrée pour cela, donc j'irais probablement avec l'option argument-to-set.

Je suis d'accord que "PATH/MANPATH/CDPATH en casse spéciale est bizarre; nous avons besoin d'une solution plus générale".

Je propose que nous ARRÊTONS la casse spéciale PATH/MANPATH/CDPATH. Ils seraient traités (par l'utilisateur final du poisson) comme ils le sont dans d'autres coquilles. $PATH (et les autres) serait une seule chaîne (ou dans le jargon du poisson une liste d'une longueur de 1) avec des deux-points. Notez que je fais référence à l'expérience de l'utilisateur du poisson, et non à la façon dont ces choses sont gérées en interne ; Je ne sais pas à quoi ressemblerait la mise en œuvre à l'intérieur du poisson - je compte sur les autres pour signaler tout problème là-bas.

Certes, cela aurait l'inconvénient d'une incompatibilité descendante, mais je pense que cela en vaudrait la peine car un gros gain de simplicité et d'élégance. Je pense que cela concernerait également le #2090.

Qu'en pense tout le monde ?

5245 a été fusionné, donc cela semble résolu.

Cette page vous a été utile?
0 / 5 - 0 notes