quel est l'équivalent zsh de l'exportation -f de bash

24

J'ai donc commencé à utiliser zsh. Je l'aime bien. Cela semble très cool et lisse, et le fait que le répertoire de travail actuel et la ligne de commande réelle soient sur des lignes différentes est sympa, mais en même temps, je remarque que cela zshpeut être un peu plus lent que bash, surtout lors de l'impression de texte sur le écran.

Ce que j'ai préféré, c'est le fait qu'il zshétait «rétrocompatible» avec toutes les fonctions que j'ai définies dans mon .bashrc.

Un reproche cependant. Toutes les fonctions fonctionnent parfaitement, mais je ne peux pas comprendre comment fonctionne le système d'exportation.

J'ai .bashrcexporté certaines de ces fonctions afin de pouvoir les utiliser ailleurs, comme dans des scripts et des programmes externes, avec export -f.

Dans zsh, l'exportation ne semble même pas être discutée. S'agit-il d'un chargement automatique? Ces deux choses sont-elles les mêmes? J'ai beaucoup de mal à comprendre cela.

ixtmixilix
la source
2
C'est une très vieille question, mais je veux dire que "le répertoire de travail actuel et la ligne de commande réelle sont sur des lignes différentes" n'a rien à voir avec zsh. Cela dépend de la façon dont vous configurez votre invite, c'est tout.
4ae1e1

Réponses:

11

Les variables d'environnement contenant des fonctions sont un hack bash. Zsh n'a rien de similaire. Vous pouvez faire quelque chose de similaire avec quelques lignes de code. Les variables d'environnement contiennent des chaînes; les anciennes versions de bash, avant la découverte de Shellshock , stockaient le code de la fonction dans une variable dont le nom est celui de la fonction et dont la valeur est () {suivie du code de la fonction suivi de }. Vous pouvez utiliser le code suivant pour importer des variables avec cet encodage et tenter de les exécuter avec des paramètres de type bash. Notez que zsh ne peut pas émuler toutes les fonctionnalités de bash, tout ce que vous pouvez faire est de vous rapprocher un peu (par exemple, pour $foodiviser la valeur et étendre les caractères génériques, et créer des tableaux basés sur 0).

bash_function_preamble='
    emulate -LR ksh
'
for name in ${(k)parameters}; do
  [[ "-$parameters[name]-" = *-export-* ]] || continue
  [[ ${(P)name} = '() {'*'}' ]] || continue
  ((! $+builtins[$name])) || continue
  functions[$name]=$bash_function_preamble${${${(P)name}#"() {"}%"}"}
done

(Comme l'a noté Stéphane Chazelas , le découvreur d'origine de Shellshock, une version antérieure de cette réponse pourrait exécuter du code arbitraire à ce stade si la définition de la fonction était incorrecte. Cette version ne fonctionne pas, mais bien sûr dès que vous exécutez une commande, il peut s'agir d'une fonction importée de l'environnement.)

Les versions post-Shellshock des fonctions d'encodage bash dans l'environnement utilisent des noms de variables invalides (par exemple BASH_FUNC_myfunc%%). Cela les rend plus difficiles à analyser de manière fiable car zsh ne fournit pas d'interface pour extraire ces noms de variables de l'environnement.

Je ne recommande pas de faire ça. Se fier aux fonctions exportées dans les scripts est une mauvaise idée: cela crée une dépendance invisible dans votre script. Si jamais vous exécutez votre script dans un environnement qui n'a pas votre fonction (sur une autre machine, dans une tâche cron, après avoir changé vos fichiers d'initialisation du shell,…), votre script ne fonctionnera plus. Au lieu de cela, stockez toutes vos fonctions dans un ou plusieurs fichiers séparés (quelque chose comme ~/lib/shell/foo.sh) et démarrez vos scripts en important les fonctions qu'il utilise ( . ~/lib/shell/foo.sh). De cette façon, si vous modifiez foo.sh, vous pouvez facilement rechercher les scripts qui en dépendent. Si vous copiez un script, vous pouvez facilement trouver les fichiers auxiliaires dont il a besoin.

Zsh (et ksh avant) rend cela plus pratique en fournissant un moyen de charger automatiquement les fonctions dans les scripts où elles sont utilisées. La contrainte est que vous ne pouvez mettre qu'une seule fonction par fichier. Déclarez la fonction comme chargée automatiquement et placez la définition de la fonction dans un fichier dont le nom est le nom de la fonction. Placez ce fichier dans un répertoire répertorié dans $fpath(que vous pouvez configurer via la FPATHvariable d'environnement). Dans votre script, déclarez les fonctions chargées automatiquement avec autoload -U foo.

De plus, zsh peut compiler des scripts, pour gagner du temps d'analyse. Appelez zcompilepour compiler un script. Cela crée un fichier avec l' .zwcextension. Si ce fichier est présent autoload, le fichier compilé sera chargé à la place du code source. Vous pouvez utiliser la zrecompilefonction pour (re) compiler toutes les définitions de fonction dans un répertoire.

Gilles 'SO- arrête d'être méchant'
la source
1
C'est drôle comme votre code a la même vulnérabilité shellshock bash(ne vérifie pas que le contenu de la variable n'est qu'une définition de fonction et traite n'importe quel nom de variable comme HTTP_HOSTou LC_X). Bonne réponse sinon.
Stéphane Chazelas
@ StéphaneChazelas Si vous allez exécuter des commandes avec des fonctions importées de l'environnement, vous avez quasiment perdu. Mais j'ai mis à jour le code d'importation pour ne pas exécuter de code arbitraire. Il n'est cependant pas très utile, car bash post-shellshock n'encode pas ses fonctions exportées de la même manière.
Gilles 'SO- arrête d'être méchant'
Vous avez maintenant corrigé l'équivalent de CVE-2014-6271, mais vous êtes toujours probablement exposé à de nombreuses vulnérabilités du type de CVE-2014-6277 / 6278 ... car vous exposez toujours l'analyseur zsh au code dans n'importe quelle variable y compris certains qui sont potentiellement sous le contrôle des attaquants dans certains contextes (car le code dans zsh -c 'functions[f]=$VAR' est analysé même si la ffonction n'est jamais appelée). La solution consiste à ne considérer que les variables dont le nom suit un modèle réservé comme ceux-ci $BASH_FUNC_x%%, mais comme vous le dites, zshn'a pas d'API pour les répertorier ou les récupérer. Vous auriez besoin d'appeler perlpar exemple.
Stéphane Chazelas
7

Si vous mettez votre déclaration de fonction dans .zshenv , votre fonction sera utilisable à partir d'un script sans aucun effort.

des voyous
la source
Pourquoi avez-vous dévalorisé ma réponse? S'il vous plaît, expliquez.
rools
Toujours en attente d'une réponse et toujours en marche!
rools
Je viens de découvrir cette réponse et c'est une solution idéale.
AFH
Je ne l'ai pas dévalorisé. Et TBH le PO demandait à exporter des trucs à partir de .bashrc, ce qui est une sorte de mauvaise idée, mieux vaut le mettre dans un script afin de ne pas se retrouver avec un environnement énorme. Mais votre solution n'est qu'une variante de cette même mauvaise idée, mettez tous vos scripts .zshenvdedans et cela ralentit chaque invocation de zsh en analysant beaucoup de code qui n'est jamais utilisé. De plus, ce n'est pas la même chose que l'exportation d'une fonction, tout comme une variable exportée, une fonction exportée n'est disponible que pour les processus enfants. Alors que le contenu que vous mettez .zshenvest disponible pour tous les zsh.
Metamorphic
Enfin, si vous comptez sur le code personnel que vous avez mis dans votre .zshenv, tous vos scripts seront totalement non portables. Normalement, les scripts peuvent dépendre les uns des autres, ce qui est bien, vous les distribuez ensemble. Mais s'ils dépendent de la présence de fonctions spéciales dans .zshenv, personne ne voudra les utiliser, ou ils devraient être invoqués avec un spécial ZDOTDIR, empêchant la vôtre .zshenvd'être exécutée. Ce serait pénible.
Metamorphic