Separate Namespaces für Funktionen und Variablen in POSIX-Shells

13

Im Bindestrich scheinen Funktionen und Variablen in separaten Namespaces zu leben:

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

Handelt es sich um eine dash-spezifische Funktion oder eine POSIX-Garantie?

PSkocik
quelle
2
Ihr Code beweist nicht, dass sich die fnFunktion in einem separaten Namespace befindet. Wenn die einmalige Ausführung die Definition gelöscht hätte, würden wir genau dasselbe Verhalten feststellen. Sie sollten zeigen, dass die Funktion noch definiert ist, zB mit type fndanach.
Alexis

Antworten:

13

Eine Garantie :

2.9.5 Befehl zur Funktionsdefinition

Eine Funktion ist ein benutzerdefinierter Name, der als einfacher Befehl zum Aufrufen eines zusammengesetzten Befehls mit neuen Positionsparametern verwendet wird. Eine Funktion wird mit einem "Funktionsdefinitionsbefehl" definiert. [...]

Die Funktion heißt fname; Die Anwendung muss sicherstellen, dass es sich um einen Namen handelt (siehe XBD-Namen) und dass es sich nicht um den Namen eines speziellen integrierten Dienstprogramms handelt. Eine Implementierung kann andere Zeichen in einem Funktionsnamen als Erweiterung zulassen. Die Implementierung muss separate Namensräume für Funktionen und Variablen verwalten.

ilkkachu
quelle
Beachten Sie auch , dass unsethat -vund -fzwischen unsetting die Variable oder Funktion mit dem gegebenen Namen zu wählen. bash(im Gegensatz zu den meisten anderen Schalen gegen) wird unset die foo Funktion mit , unset foowenn es keine fooVariable (!), ein Verhalten von POSIX erlaubt. Aus diesem Grund ist es in POSIX-Skripten empfehlenswert, immer entweder -voder zu verwenden -f(und natürlich auch in bashSkripten. Beachten Sie jedoch, dass das unsetSetzen einer Variablen in nicht immer möglich ist bash, da das bashVariablenscoping einige Probleme aufweist).
Stéphane Chazelas
Beachten Sie, dass Sie in Pre-Shellshock-Bash Probleme haben, wenn Sie sowohl die Variable als auch die Funktion unter einem bestimmten Namen exportieren, da Bash für beide denselben Umgebungsvariablennamen verwenden würde (wenn Sie ihn zweimal in der Umgebung ablegen, könnten einige Befehle ihn entfernen) einer von ihnen)
Stéphane Chazelas
8

Variablen und Funktionen befinden sich in verschiedenen Namespaces im Bindestrich. Dies wird auch von POSIX angegeben :

Die Implementierung muss separate Namensräume für Funktionen und Variablen verwalten.

Darüber hinaus haben Variablen standardmäßig einen globalen Gültigkeitsbereich. Einige Shells (z. B. bash, ksh und zsh) bieten das localSchlüsselwort zum Deklarieren von Variablen in einer Funktion mit ausschließlich lokalem Gültigkeitsbereich.

Ja, das Verhalten, das Sie sehen, wird von POSIX garantiert.

POSIX ist nicht standardisiert local , doch :

Die Beschreibung von Funktionen in einem frühen Vorschlag basierte auf der Vorstellung, dass Funktionen sich wie Miniatur-Shell-Skripte verhalten sollten. Mit Ausnahme der Freigabe von Variablen sollten sich die meisten Elemente einer Ausführungsumgebung so verhalten, als ob sie eine neue Ausführungsumgebung wären.

[..] Lokale Variablen innerhalb einer Funktion wurden berücksichtigt und in einen anderen frühen Vorschlag aufgenommen (gesteuert durch die spezielle integrierte Funktion local), wurden jedoch entfernt, weil sie nicht zu dem für Funktionen entwickelten einfachen Modell passen und es noch einige Einwände gegen das Hinzufügen gab Ein weiterer neuer Spezialeinbau, der nicht Teil der historischen Praxis war. Implementierungen sollten den Bezeichner local(sowie den typesetin der KornShell verwendeten) für den Fall reservieren , dass dieser lokale Variablenmechanismus in einer zukünftigen Version dieses Standards übernommen wird.

(Hervorhebung von mir)

maxschlepzig
quelle
Asche (aus den späten 80er Jahren) , auf der Basis Strich hat auch ist local, eines der beständigsten Schnittstellen gibt ( im Vergleich zu der stark ein in bash zum Beispiel gebrochen), bash erst vor kurzem nur (4.4) der geliehene local -für (für die lokalen Bereich options) from ash (Implementierung eines $-Aschestils nur für diese eine Variable). ksh und yash haben nicht local(nur die pdksh-Varianten haben local), sondern typeset(in ksh93 typesetwird lokaler (statischer) Geltungsbereich nur in Funktionen bereitgestellt, die mit der ksh-Syntax deklariert wurden).
Stéphane Chazelas