Co to jest ekspansja pośrednia? Co oznacza $ {! Var *}?


85

Czytam „ Bash Guide for Beginners ”. To mówi:

Jeśli pierwszy znak PARAMETERjest wykrzyknikiem, Bash używa wartości zmiennej utworzonej z reszty PARAMETERjako nazwy zmiennej; ta zmienna jest następnie interpretowana i ta wartość jest używana w pozostałej części podstawiania, a nie jako wartość PARAMETERsama w sobie. Jest to znane jako ekspansja pośrednia.

Podany przykład to:

franky ~> echo ${!N*}
NNTPPORT NNTPSERVER NPX_PLUGIN_PATH

Nie całkiem rozumiem tutaj:

wartość zmiennej utworzonej z reszty PARAMETER

Ponieważ PARAMETERto właśnie !N*, a następnie

reszta PARAMETER

jest po prostu N*. Jak to może tworzyć zmienną? Czy Bash przeszukał tam wszystkie możliwe polecenia?

Odpowiedzi:


110

Jeśli przeczytasz bashstronę podręcznika , w zasadzie potwierdza to, co powiedziałeś:

Jeśli pierwszym znakiem parametru jest wykrzyknik ( !), wprowadzany jest poziom pośredniej zmiennej. Bash używa wartości zmiennej utworzonej z reszty parametru jako nazwy zmiennej; ta zmienna jest następnie interpretowana i ta wartość jest używana w pozostałej części podstawiania zamiast wartości samego parametru. Jest to znane jako ekspansja pośrednia.

Jednak czytając dalej:

Wyjątkami od tej reguły są rozszerzenia ${!prefix*}i ${!name[@]}opisane poniżej.

${!prefix*}Nazwy pasujące do prefiksu. Interpretowane jako nazwy zmiennych, których nazwy rozpoczynają się od przedrostka, oddzielone pierwszym znakiem IFSzmiennej specjalnej.

Innymi słowy, Twój konkretny przykład ${!N*}jest wyjątkiem od zacytowanej reguły. To jest jednak praca jako reklamowane w oczekiwanych przypadkach, takich jak:

$ export xyzzy=plugh ; export plugh=cave

$ echo ${xyzzy}  # normal, xyzzy to plugh
plugh

$ echo ${!xyzzy} # indirection, xyzzy to plugh to cave
cave

1
Dziękuję za odpowiedź. Im więcej czytam „Bash guide for Beginners”, tym bardziej zadaję sobie pytanie, czy autorka rozumie, co pisze.
— LRDPRDX

23

Wydaje się, że istnieje wyjątek, gdy dane „pośrednie” kończy się na a *, tak jak ma to miejsce w tym przypadku. W tym przypadku podaje wszystkie nazwy zmiennych zaczynające się od określonej części ( Ntutaj). Bash może to zrobić, ponieważ śledzi zmienne i wie, które z nich istnieją.

Prawdziwe pośrednie jest to:
powiedzmy, że mam $VARIABLEustawioną zmienną 42i mam inną zmienną $NAMEustawioną na VARIABLE. ${!NAME}da mi 42. Używasz wartości jednej zmiennej, aby podać nazwę innej:

$ NAME="VARIABLE"
$ VARIABLE=42
$ echo ${!NAME}
42

5
Wow, kto wiedział, że tak łatwo jest uzyskać odpowiedź na temat sensu życia, wszechświata i wszystkiego!
— KomodoDave

3

Tak, wyszukuje wszystkie możliwe rozszerzenia zmiennych po!. Jeśli zrobiłeś:

echo ${!NP*}

dostaniesz tylko NPX_PLUGIN_PATH.

Rozważmy następujący przykład:

:~> export myVar="hi"
:~> echo ${!my*}
    myVar
:~> export ${!my*}="bye"
:~> echo $myVar
    bye

czy inne zmienne, które pasują do mojego *, również zostaną ustawione na „pa”?
— Anthony

1
@Anthony Wypróbowałem to i jeśli ${!my*}rozszerza się do myA, myB, myA jest eksportowane ze swoją bieżącą wartością, a myB jest ustawione na „bye” i wyeksportowane. Niezbyt przydatne.
— GKFX

3

Trafiłeś w wyjątek w przetwarzaniu pośrednim, gdzie jeśli ostatnim znakiem jest *, zwrócone zostaną wszystkie zmienne, które mają wcześniej podany prefiks.


Więc poza *przypadkiem, czy to to samo co ${${VAR}}?
— chronospoon

1
@chronospoon,, w skrócie z ${${VAR}}możliwością zapisu, ponieważ ${$VAR}nie jest legalne, ponieważ $VARzwraca ciąg znaków, który nie może występować po $znaku; aby użyć łańcucha jako nazwy zmiennej, musisz wprowadzić jeden poziom pośredni (jak podano w samym oryginalnym pytaniu), tj. możesz użyć ${!VAR}, który robi dokładnie to, czego się spodziewałeś (błędnie, ale zrozumiale) ${$VAR}.
— Enrico,

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.