Oddzielne przestrzenie nazw dla funkcji i zmiennych w powłokach POSIX

13

W myślniku funkcje i zmienne wydają się żyć w oddzielnych przestrzeniach nazw:

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

Czy jest to funkcja specyficzna dla myślnika czy gwarancja POSIX?

PSkocik
źródło
2
Twój kod nie dowodzi, że fnfunkcja znajduje się w osobnej przestrzeni nazw; jeśli wykonanie go raz wyczyściło jego definicję, zobaczylibyśmy dokładnie to samo zachowanie. Powinieneś pokazać, że funkcja jest nadal zdefiniowana, np type fn. Później.
Alexis

Odpowiedzi:

13

Gwarancja :

2.9.5 Polecenie definicji funkcji

Funkcja jest nazwą zdefiniowaną przez użytkownika, która jest używana jako proste polecenie do wywołania polecenia złożonego z nowymi parametrami pozycyjnymi. Funkcja jest definiowana za pomocą „polecenia definicji funkcji”. [...]

Funkcja nazywa się fname; aplikacja powinna upewnić się, że jest to nazwa (patrz Nazwa XBD) i że nie jest to nazwa specjalnego wbudowanego narzędzia. Implementacja może dopuszczać inne znaki w nazwie funkcji jako rozszerzenie. Implementacja powinna utrzymywać osobne przestrzenie nazw dla funkcji i zmiennych.

ilkkachu
źródło
Zauważ też, że unsetma -vi -fdo wyboru rozbrojenie zmiennej lub funkcji o podaną nazwę. bash(w przeciwieństwie do większości innych powłok) będzie rozbroić foo funkcję ze unset foojeśli nie ma foozmienny (!), zachowanie dozwolonych przez POSIX. Dlatego w skryptach POSIX dobrą praktyką jest zawsze używanie jednego -vlub -f(i oczywiście również w bashskryptach, ale należy pamiętać, że unsetnie zawsze może to rozbroić zmienną bash, bashzakres skalowania ma sporo problemów).
Stéphane Chazelas
Zauważ, że w bashu przed shellshockiem wystąpiłyby problemy podczas eksportowania zarówno zmiennej, jak i funkcji o podanej nazwie, ponieważ bash skończyłby dla nich tą samą nazwą zmiennej środowiskowej (umieszczając ją dwukrotnie w środowisku, niektóre polecenia mogłyby usunąć jeden z nich)
Stéphane Chazelas
8

Zmienne i funkcje znajdują się w różnych obszarach nazw w myślniku i jest to również określone przez POSIX :

Implementacja powinna utrzymywać osobne przestrzenie nazw dla funkcji i zmiennych.

Oprócz tego zmienne mają domyślnie zasięg globalny. Niektóre powłoki (np. Bash, ksh i zsh) zapewniają localsłowo kluczowe do deklarowania zmiennych w funkcji tylko o zasięgu lokalnym.

Tak, więc zachowanie, które widzisz jest gwarantowane przez POSIX.

POSIX nie znormalizowane local , ale :

Opis funkcji we wczesnej propozycji opierał się na założeniu, że funkcje powinny zachowywać się jak miniaturowe skrypty powłoki; to znaczy, oprócz współużytkowania zmiennych , większość elementów środowiska wykonawczego powinna zachowywać się tak, jakby były nowym środowiskiem wykonawczym, [..]

[..] Zmienne lokalne w ramach funkcji zostały uwzględnione i uwzględnione w innej wczesnej propozycji (kontrolowanej przez specjalne wbudowane local), ale zostały usunięte, ponieważ nie pasują do prostego modelu opracowanego dla funkcji i ponieważ istnieje pewien sprzeciw wobec dodawania jeszcze kolejny nowy specjalny wbudowany element, który nie był częścią praktyki historycznej. Implementacje powinny zarezerwować identyfikator local(jak również typeset, jak używany w KornShell) na wypadek, gdyby ten mechanizm zmiennej lokalnej został przyjęty w przyszłej wersji tego standardu.

(moje podkreślenie)

maxschlepzig
źródło
ash (z późnych lat 80.), na którym oparty jest również myślnik, ma localjeden z najbardziej spójnych interfejsów (w porównaniu do poważnie zepsutego na przykład w bash), bash dopiero niedawno (4.4) pożyczył local -(dla zasięgu lokalnego opcje) z popiołu (wdrożenie zakresu w stylu popiołu tylko dla tej jednej $-zmiennej). ksh i yash nie mają local( mają tylko warianty pdksh local), ale typesetzamiast tego (w ksh93 typesetzapewnia lokalny (statyczny) zasięg tylko w funkcjach zadeklarowanych przy użyciu składni ksh).
Stéphane Chazelas