Espaces de noms séparés pour les fonctions et les variables dans les shells POSIX

13

Dans le tiret, les fonctions et les variables semblent vivre dans des espaces de noms distincts:

fn(){
    fn="hello world"
}
fn; echo "The value is $fn!" #prints: The value is hello world!
fn; echo "The value is $fn!" #prints: The value is hello world!
#the fn variable doesn't conflict with the fn function

Est-ce une fonctionnalité spécifique au tableau de bord ou une garantie POSIX?

PSkocik
la source
2
Votre code ne prouve pas réellement que la fnfonction se trouve dans un espace de noms séparé; si l'exécuter une fois avait effacé sa définition, nous verrions exactement le même comportement. Vous devez montrer que la fonction est toujours définie, par exemple avec type fnaprès.
alexis

Réponses:

13

Une garantie :

2.9.5 Commande de définition de fonction

Une fonction est un nom défini par l'utilisateur qui est utilisé comme une simple commande pour appeler une commande composée avec de nouveaux paramètres de position. Une fonction est définie avec une "commande de définition de fonction". [...]

La fonction est nommée fname; l'application doit s'assurer qu'il s'agit d'un nom (voir Nom XBD) et qu'il ne s'agit pas du nom d'un utilitaire intégré spécial. Une implémentation peut autoriser d'autres caractères dans un nom de fonction en tant qu'extension. L'implémentation doit conserver des espaces de noms séparés pour les fonctions et les variables.

ilkkachu
la source
Notez également que unseta -vet -fpour choisir entre la suppression de la variable ou de la fonction par le nom donné. bash(contrairement à la plupart des autres shells) désactive la foo fonction avec unset foos'il n'y a pas de foovariable (!), un comportement autorisé par POSIX. C'est pourquoi dans les scripts POSIX, il est recommandé de toujours utiliser l'un -vou l' autre -f(et bien sûr dans les bashscripts également, mais notez que unsetcela ne désactive pas toujours une variable dans bash, la bashportée des variables a pas mal de problèmes).
Stéphane Chazelas
Notez que dans bash pré-shellshock, vous auriez des problèmes lors de l'exportation à la fois de la variable et de la fonction par un nom donné, car bash finirait par utiliser le même nom de variable d'environnement pour les deux (en le mettant deux fois dans l'environnement, certaines commandes pourraient supprimer l'un d'eux)
Stéphane Chazelas
8

Les variables et les fonctions résident dans différents espaces de noms dans le tiret et cela est également spécifié par POSIX :

L'implémentation doit conserver des espaces de noms séparés pour les fonctions et les variables.

En plus de cela, les variables ont une portée globale, par défaut. Certains shells (par exemple bash, ksh et zsh) fournissent le localmot - clé pour déclarer les variables dans une fonction à portée locale uniquement.

Donc, oui, le comportement que vous voyez est garanti par POSIX.

Posix n'a pas normalisé local , encore :

La description des fonctions dans une première proposition était basée sur la notion que les fonctions devraient se comporter comme des scripts shell miniatures; c'est-à-dire que, sauf pour le partage de variables , la plupart des éléments d'un environnement d'exécution devraient se comporter comme s'ils étaient un nouvel environnement d'exécution, [..]

[..] Les variables locales au sein d'une fonction ont été prises en compte et incluses dans une autre proposition antérieure (contrôlée par la fonction intégrée spéciale local), mais ont été supprimées car elles ne correspondent pas au modèle simple développé pour les fonctions et parce qu'il y avait une certaine opposition à l'ajout un autre nouveau spécial intégré qui ne faisait pas partie de la pratique historique. Les implémentations doivent réserver l'identifiant local(ainsi que typesetcelui utilisé dans KornShell) au cas où ce mécanisme de variable locale serait adopté dans une future version de cette norme.

(c'est moi qui souligne)

maxschlepzig
la source
ash (à partir de la fin des années 80) sur lequel est basé le tiret a également local, l'une des interfaces les plus cohérentes (par rapport à celle gravement cassée dans bash par exemple), bash vient récemment (4.4) d'emprunter le local -(pour la portée locale pour options) de ash (implémentation de la portée de style ash pour cette seule $-variable). ksh et yash n'en ont pas local(seules les variantes pdksh en ont local), mais en ont à la typesetplace (dans ksh93 typesetfournit une portée locale (statique) uniquement dans les fonctions déclarées en utilisant la syntaxe ksh).
Stéphane Chazelas