Co to jest “ zadeklarować ” w Bash?

Po przeczytaniu odpowiedzi ilkkachu „na to pytanie dowiedziałem się o istnieniu declare (z argumentem -n) wbudowana powłoka.

help declare przynosi:

Ustaw wartości zmiennych i atrybuty.

Zadeklaruj zmienne i nadaj im atrybuty. Jeśli nie podano NAZW, wyświetl atrybuty i wartości wszystkich zmiennych.

-n … uczyń NAZWĘ odniesieniem do zmiennej nazwanej na podstawie jej wartości

I poproś o ogólne wyjaśnienie z przykładem dotyczącym declare, ponieważ nie rozumiem man. Wiem, co to jest zmienna i ją rozwijam, ale nadal brakuje mi man na declare (atrybut zmiennej?).

Może chciałbyś to wyjaśnić w oparciu o kod ilkkachu w odpowiedzi:

#!/bin/bash function read_and_verify { read -p "Please enter value for "$1": " tmp1 read -p "Please repeat the value to verify: " tmp2 if [ "$tmp1" != "$tmp2" ]; then echo "Values unmatched. Please try again."; return 2 else declare -n ref="$1" ref=$tmp1 fi } 

Komentarze

Odpowiedź

W większości przypadków wystarczy niejawna deklaracja w bash

asdf="some text" 

Ale czasami chcesz, aby wartość zmiennej była tylko liczbą całkowitą (więc w przypadku późniejszej zmiany, nawet automatycznie, można ją zmienić tylko na liczba całkowita, w niektórych przypadkach domyślnie zero) i może zawierać:

declare -i num 

lub

declare -i num=15 

Czasami potrzebujesz tablic, a potem potrzebujesz declare

declare -a asdf # indexed type 

lub

Dobre samouczki dotyczące tablic można znaleźć w bash podczas przeglądania Internetu za pomocą ciągu wyszukiwania„ bash array tutorial ”(bez cudzysłowów), dla przykład

linuxconfig.org/how-to-use-arrays-in-bash-script


Myślę, że są to najczęstsze przypadki, gdy deklarujesz zmienne.


Zwróć również uwagę, że

  • w funkcji declare czyni zmienną lokalną (w funkcji)
  • bez nazwy, wyświetla wszystkie zmienne (w aktywnej powłoce)

    declare 

Na koniec otrzymujesz krótkie podsumowanie funkcji wbudowanego polecenia powłoki declare w bash poleceniem

help declare 

Komentarze

  • Witam z OP! Myślę, że twoja odpowiedź jest świetna i zagłosowałem za nią i dziękuję za tę, moim zdaniem, bardzo dydaktyczną odpowiedź. Właśnie zasugerowałem drobną edycję, która moim skromnym zdaniem uczyni ją jeszcze łatwiejszą i bardziej przystępną dla nowoprzybyłych do czytania; proszę przejrzyj tę sugestię.
  • Właśnie zobaczyłem, że user:muru głosowało za odrzuceniem edycji; proszę wiedzieć, że ja i muru ” starliśmy się ” kilka razy w różnych sekcjach tej witryny i zakładam, że jego odrzucenie nie jest ' t obiektywny i jest faktycznie szkodliwy w przeciwieństwie do bezpośrednich zmian przedstawionych na stronie sugestii edycji tutaj: unix.stackexchange.com/review/suggested -edits / 325749
  • @JohnDoea, zauważyłem, że również inny użytkownik odrzucił Twoje zmiany. Myślę, że niektóre z twoich poprawek są dobre, ale niektóre z nich zmienią przekaz z tego, co zamierzałem, więc nie podobają mi się. Mogę edytować odpowiedź, aby uwzględnić to, co uważam za dobre zmiany.
  • dziękuję; jak zapewne wiesz, odrzucanie zmian jest znacznie częstsze w SE niż akceptowanie ich (nawet częściowo); dziękuję za poinformowanie mnie, że inny użytkownik odrzucił edycję (szczerze ' nie widziałem wcześniej) i za rozważenie wstawienia przynajmniej niektórych moich zmian do Twojej odpowiedzi; Bardzo to szanuję,

Odpowiedź

Wynik help declare jest dość lakoniczny. Jaśniejsze wyjaśnienie można znaleźć w man bash lub info bash – ten ostatni jest źródłem tego, co poniżej.

Najpierw kilka definicji. Informacje o zmiennych i atrybutach :

Parametr to jednostka przechowująca wartości. … zmienna to parametr oznaczony jako name. Zmienna ma wartość i zero lub więcej atrybutów . Atrybuty są przypisywane za pomocą wbudowanego polecenia declare

Oraz o declare wbudowanym :

declare

 declare [-aAfFgilnrtux] [-p] [name[=value] …]  

Zadeklaruj zmienne i nadaj im atrybuty. Jeśli nie podano nazw, wyświetl zamiast nich wartości zmiennych.

-n
Podaj każdemu nazwa atrybut nameref , czyniąc z niego odniesienie do innej zmiennej. Ta inna zmienna jest definiowana przez wartość nazwa . Wszystkie odwołania, przypisania i modyfikacje atrybutów do nazwa , z wyjątkiem tych, które używają lub zmieniają sam atrybut -n, są wykonywane na zmiennej, do której odwołuje się name wartość. …

Zwróć uwagę, że zmienne odniesienia do nazw są dostępne tylko w wersji Bash 4.3 lub nowszej 1 .

Ponadto, aby uzyskać przydatne wprowadzenie do declare i atrybutów zmiennych w Bash, wskazałbym to odpowiedz na ” Co robią declare name i declare -g? ” (choć skupia się głównie na zakresie zmiennych).


Zasadniczo 2 , declare name=[value] jest odpowiednikiem przypisania name=[value], które prawdopodobnie znasz. W obu przypadkach name ma przypisaną wartość zerową wartość, jeśli brakuje value.

Zauważ, że nieco inna declare name zamiast tego nie ustawia zmienna name 3 :

 $ declare name ## With the -p option, declare is used to display ## attributes and values of variables $ declare -p name declare -- name ## "name" exists ## Parameter expansion can be used to reveal if a variable is set: ## "isunset" is substituted to "name" only if unset $ echo "${name-isunset}" isunset  

W ten sposób zmienną name można:

  • zadeklarować i nieskonfigurowane , po declare name;
  • zadeklarowano i ustawić z null jako wartość, po name= lub declare name=;
  • zadeklarowano , ustaw i z wartością różną od null po name=value lub .

Bardziej ogólnie, declare [options] name=value

  1. tworzy zmienną name – który jest parametrem o nazwie, która z kolei jest tylko częścią pamięci, której możesz użyć do przechowywania informacji 4 ;
  2. przypisuje wartość value do niego;
  3. opcjonalnie ustawia atrybuty name „, które definiują zarówno rodzaj wartości może przechowywać (nie w kategoriach typu , ściśle rzecz biorąc, ponieważ język Basha nie jest wpisywany) i sposobów, w jakie można nim manipulować.

Atrybuty to prawdopodobnie łatwiej to wyjaśnić na przykładzie: użycie declare -i name ustawi atrybut ” integer ” z name, pozwalając na traktowanie go jako liczby całkowitej; cytowanie instrukcji , ” obliczenia arytmetyczne zostaną wykonane, gdy zmiennej zostanie przypisana wartość „:

 ## Let"s compare an ordinary variable with an integer $ declare var $ declare -i int $ var="1+1" $ int="1+1" $ echo "$var" 1+1 ## The literal "1+1" $ echo "$int" 2 ## The result of the evaluation of 1+1  

W świetle powyższe, co dzieje się w kodzie ilkkachu to:

  1. Zadeklarowano zmienną o nazwie ref, z ” nameref ” zestaw atrybutów, a zawartość $1 (pierwszy argument pozycyjny) jest przypisana do it:

     declare -n ref="$1"  

    Cel zmiennej referencyjnej nazwy, takiej jak ref ma na celu przechowywanie nazwy innej zmiennej, która generalnie nie byłaby znana z góry, prawdopodobnie dlatego, że chcemy, aby była zdefiniowana dynamicznie (np. Ponieważ chcemy ponownie użyć fragmentu kodu i mieć to zastosowane do kilku zmiennych) i do zapewniają wygodny sposób odniesienia się do niego (i manipulowania nim). (Jednak nie jedyny: pośredni jest alternatywą; zobacz Rozszerzenie parametrów powłoki ).

  2. Kiedy wartość zmiennej tmp1 jest przypisywana do ref:

     ref=$tmp1  

    dodatkowa zmienna, której nazwa jest wartością ref, jest niejawnie zadeklarowana. Wartość tmp1 jest również pośrednio przypisywana do niejawnie zadeklarowanej zmiennej za pomocą tego jawnego przypisania do ref .

W kontekście Twojego połączonego pytania , dzwoniąc pod numer read_and_verify as

 read_and_verify domain "Prompt text here..."  

zadeklaruje zmienną domain i przypisz mu wartość tmp1 (tj. dane wejściowe użytkownika). Jest dokładnie zaprojektowany, aby ponownie wykorzystać kod, który współdziała z użytkownikiem i wykorzystać zmienną odniesienia do nazwy aby zadeklarować domain i kilka innych zmiennych.

Aby przyjrzeć się bliżej niejawnej części, możemy odtworzyć proces krok po kroku:

 ## Assign a value to the first positional argument $ set -- "domain" ## Declare the same "tmp1" variable as in your code $ tmp1="value for domain" ## Declare a "ref" variable with the nameref attribute set and ## assign the value "domain" to it $ declare -n ref="$1" ## Note that there is no "domain" variable yet $ declare -p domain bash: declare: domain: not found ## Assign a value to "ref" and, indirectly, to the "domain" variable ## that is implicitly declared $ ref=$tmp1 ## Verify that a variable named "domain" now exists, and that ## its value is that of "tmp1" $ declare -p domain declare -- domain="value for domain" ## Verify that "ref" is actually a reference to "domain" $ domain="new value" $ echo "$domain" new value $ declare -p ref declare -n ref="domain" $ echo "$ref" new value  

1 Odniesienie: ZMIANY , sekcja ” 3. Nowe funkcje w Bash „, punkt ” w „.
Może to mieć znaczenie: na przykład CentOS Linux 7.6 (obecnie najnowsza wersja) jest dostarczany z Bash 4.2 .

2 Jak zwykle wbudowane powłoki, wyczerpujące i wyjaśnienie jest nieuchwytne, ponieważ wykonują różne, być może heterogeniczne działania. Skoncentruję się tylko na deklarowaniu, przypisywaniu i ustawianiu atrybutów i rozważę umieszczenie, określenie zakresu i usunięcie atrybutów poza zakresem tej odpowiedzi.

3 To zachowanie declare -p zostało wprowadzone w Bash 4.4. Odniesienie: plik CHANGES , sekcja ” 3. Nowe funkcje w Bash „, point ” f „.
Jako G-Man wskazany w komentarzach, w Bash 4.3 declare name; declare -p name zwraca błąd. Ale nadal możesz sprawdzić, czy name istnieje z declare -p | grep "declare -- name".

4 FullBashGuide, Parametry na mywiki.wooledge.org

Komentarze

  • (1) Nie mogę odtworzyć wyników pokazanych w pierwszym bloku kodu: declare name, a następnie zwraca „bash: decre: name: not found”. (Chociaż declare -p | grep na daje declare -- name.) (2) Uważam, że prezentowanie echo "${name-isunset}" w kontekście declare name, ponieważ traktuje zmienną niezadeklarowaną (tj. niezdefiniowaną) tak samo jak zadeklarowaną ale zmienna unset . (3) Może zechcesz wspomnieć, że nazwy odwołań są dostępne tylko w wersji bash 4.3 i nowszych.
  • @ G-Man Dziękuję za uwagi! Zwrócę się do nich ' tak szybko, jak to możliwe, a ' zaktualizuję odpowiedź w razie potrzeby. Jeśli chodzi o (1), mój GNU bash, version 5.0.7(1)-release (x86_64-pc-linux-gnu) w Arch Linux nadal daje wyniki, które pokazałem. Może to zachowanie zostało wprowadzone dopiero niedawno, ' zbadam to.
  • Tak; ' korzystam tylko z wersji 4.3.
  • @ G-Man Odpowiedź zaktualizowana o uwagi dotyczące (1) i (3). O (2): Chciałem pokazać, że declare x nie ' nie ustawia x, podczas gdy declare x= tak. Nie udało mi się ' znaleźć żadnego odniesienia do twierdzenia, że declare -- x (jako wynik declare -p x) oznacza ” nieustawione „, natomiast declare -- x="" oznacza ” set „; w ten sposób wprowadziłem rozwinięcie ${parameter-word}, nawet jeśli nie rozróżnia ” unset ” i ” nie ' nie istnieje „, jak wskazałeś. Jednak ' nie jestem pewien, jak mam to wyjaśnić w mojej odpowiedzi (bez odwracania uwagi czytelnika od tematu).

Odpowiedz

Spróbuję to wyjaśnić, ale wybacz mi, jeśli nie będę postępować zgodnie z podanym przez Ciebie przykładem. Raczej spróbuję poprowadzić Cię moim własnym, innym podejściem.

Mówisz, że rozumiesz już pojęcia takie jak „zmienne” i „ich rozszerzanie” itp., Więc przejdę tylko do kilku podstawowa wiedza, która w innym przypadku wymagałaby głębszego skupienia się.

Zacznę więc od tego, co najwyżej podstawowa , polecenie declare jest po prostu sposobem na poinformowanie Basha, że potrzebujesz wartości zmiennej (tj. wartości, która może się zmienić podczas wykonywania skryptu) i że będziesz odwołuj się do tej wartości, używając określonej nazwy, dokładnie takiej, którą wskazałeś obok samego polecenia declare.

To znaczy:

 declare foo="bar"  

mówi Bashowi, że chcesz, aby zmienna o nazwie foo miała wartość bar.

Ale… chwileczkę… możemy zrobić to bez użycia declare w ogóle, prawda? Jak w:

 foo="bar"  

Bardzo prawda.

Cóż , zdarza się, że powyższe proste przypisanie jest w rzeczywistości niejawnym sposobem … w rzeczywistości … zadeklarowania zmiennej.

( Zdarza się również, że powyższe jest jednym z kilku sposobów na zmień wartość zmiennej o nazwie foo; rzeczywiście jest to najbardziej bezpośrednia, zwięzły, oczywisty, prosty sposób… ale to nie jedyny…… Wrócę do tego później… ).

Ale jeśli tak jest możliwe jest zadeklarowanie „nazwy, która będzie oznaczać wartości zmiennych” (po prostu „zmienna” odtąd, ze względu na zwięzłość) bez używania declare, dlaczego miałbyś kiedykolwiek chcieć użyć tego pompatycznego polecenia „deklaruj”?

Odpowiedź leży w fakcie, że powyższe implici t sposób na zadeklarowanie zmiennej (foo="bar"), to .. niejawnie .. sprawia, że Bash uważa tę zmienną za typ, który jest najczęściej używany w typowym scenariuszu użycia powłoki .

Takim typem jest string, czyli ciąg znaków bez określonego znaczenia. Dlatego łańcuch jest tym, co otrzymujesz, gdy używasz niejawnej deklaracji.

Ale ty, jako programista, czasami musisz raczej rozważyć zmienną jako np. Liczbę … na której musisz wykonać arytmetykę operacje … i użycie niejawnej deklaracji, takiej jak foo=5+6 nie spowoduje , że Bash przypisze wartość 11 do foo as można się spodziewać. Raczej przypisze foo sekwencję trzech znaków 5 + 6.

Więc … potrzebujesz sposobu, aby powiedzieć Bashowi, że chcesz, aby foo był traktowany jako liczba, a nie string .. i do tego właśnie przydaje się jawne declare.

Po prostu powiedz:

 declare -i foo=5+6 # <<- note the "-i" option: it means "integer"  

, a Bash z radością wykona obliczenia za Ciebie i przypisze numeryczną wartość 11 do zmiennej foo.

To znaczy: mówiąc declare -i foo dajesz zmiennej foo atrybut bycia liczbą całkowitą.

Zadeklarowanie liczb (dokładnie liczb całkowitych, ponieważ Bash nadal nie rozumie liczb dziesiętnych, zmiennoprzecinkowych itp.) może być pierwszym powodem użycia declare, ale to nie jedyny powód. Jak już zrozumiałeś, istnieje kilka innych atrybutów, które możesz nadać zmiennym. Na przykład możesz poprosić Bash, aby zawsze zapisywał wartość zmiennej jako wielką, bez względu na wszystko: jeśli powiesz declare -u foo, a następnie powiesz foo=bar Bash w rzeczywistości przypisuje ciąg BAR do zmiennej foo.

W celu nadania któregokolwiek z tych atrybutów do zmiennej, musisz użyć polecenia declare, nie ma innego wyjścia.


Teraz jeszcze jedna z opcji atrybuty, które możesz nadać za pomocą declare to niesławny atrybut „name-ref”, atrybut -n. ( A teraz mam zamiar wznowić koncepcję, którą wcześniej zawiesiłem ).

Atrybut name-ref, w zasadzie, pozwala programistom Bash na inny sposób zmiany wartości zmiennej. Dokładniej daje to pośredni sposób zrobienia tego.

Oto jak to działa:

Ty declare zmienną mającą atrybut -n i jest to bardzo zalecane (choć nie jest to ściśle wymagane, ale to upraszcza), aby podać również wartość tej bardzo zmiennej tej samej declare polecenie. W ten sposób:

 declare -n baz="foo"  

To mówi Bashowi, że od tej pory on, za każdym razem, gdy użyjesz lub zmienisz wartość zmiennej o nazwie baz, będzie ona faktycznie wykorzystywać lub zmieniać wartość zmiennej o nazwie foo.

Co oznacza, że od tego momentu yo Możesz powiedzieć na przykład baz=10+3, aby foo uzyskało wartość 13.Zakładając oczywiście, że foo zostało wcześniej zadeklarowane jako liczba całkowita (declare -i), tak jak to zrobiliśmy minutę temu, w przeciwnym razie otrzyma sekwencję z czterech znaków 1 0 + 3.

Ponadto: jeśli zmienisz bezpośrednio wartość foo, jak w foo=15, zobaczysz 15 również mówiąc echo “${baz}”. Dzieje się tak, ponieważ zmienna baz zadeklarowana jako nazwa-ref w foo zawsze odzwierciedla foo wartość.

Powyższe polecenie declare -n nazywane jest „odniesieniem do nazwy”, ponieważ tworzy zmienną baz odnoszą się do nazwy innej zmiennej. W rzeczywistości zadeklarowaliśmy, że baz ma wartość „foo”, która z powodu opcji -n jest obsługiwana przez Bash jako nazwę dla kolejna zmienna.

Teraz dlaczego na Ziemi chciałbyś to zrobić?

Cóż … warto powiedzieć, że jest to funkcja dla dość zaawansowanych potrzeb.

W rzeczywistości tak zaawansowana, że gdy programista napotyka problem, który naprawdę wymagałby odniesienia do nazwy, jest to również prawdopodobne, że taki problem powinien być raczej rozwiązany za pomocą odpowiedniego języka programowania zamiast Bash.

Jedną z tych zaawansowanych potrzeb jest na przykład sytuacja, gdy jako programista nie możesz wiedzieć podczas programowania której zmiennej będziesz musiał użyć w określonym miejscu skryptu, ale będzie w pełni znana dynamicznie w czasie wykonywania. Biorąc pod uwagę, że żaden programista nie może interweniować w czasie wykonywania, jedyną opcją jest zapewnienie wcześniej takiej sytuacji w skrypcie, a „odniesienie do nazwy” może być jedynym wykonalnym sposób. Jako szeroko znany przypadek użycia tej zaawansowanej potrzeby, pomyśl na przykład o wtyczkach. Programista programu „obsługującego wtyczki” musi wcześniej przygotować ogólne zabezpieczenia dla przyszłych (i być może stron trzecich) wtyczek. Dlatego programista będzie musiał korzystać z udogodnień takich jak nazwa-ref w Bash.

Inną zaawansowaną potrzebą jest sytuacja, gdy masz do czynienia z ogromną ilością danych w pamięci RAM, a również musisz przekazać te dane do funkcji twojego skryptu, które także muszą modyfikować te dane po drodze. W takim przypadku z pewnością możesz skopiować te dane z jednej funkcji do drugiej (tak jak robi to Bash, gdy robisz dest_var="${src_var}" lub gdy wywołujesz funkcje takie jak myfunc "${src_var}"), ale ponieważ są to ogromne ilości danych, spowodowałoby to ogromne marnotrawstwo pamięci RAM i dla bardzo nieefektywnej operacji. Dlatego Rozwiązaniem w takich sytuacjach jest użycie nie kopii danych, ale odniesienie do tych danych. W Bash, nazwa-ref. Ten przypadek użycia jest naprawdę normą w każdym nowoczesnym języku programowania, ale jest dość wyjątkowy, jeśli chodzi o Bash, ponieważ Bash jest głównie zaprojektowany dla krótkich prostych skryptów, które głównie zajmują się plikami i poleceniami zewnętrznymi, a zatem skrypty Bash rzadko muszą przejść ogromne ilość danych między funkcjami. A kiedy funkcje skryptu muszą udostępniać pewne dane (uzyskiwać do nich dostęp i modyfikować), zwykle osiąga się to przez użycie zmiennej globalnej, co jest dość normą w skryptach Bash, tak samo jak bardzo przestarzałe w odpowiednich językach programowania.

Następnie może istnieć znaczący przypadek użycia referencji nazw w Bash i (może ironicznie) jest on powiązany z innymi typami zmiennych:

  1. zmienne zadeklarowane jako „tablice indeksowane” (declare -a)
  2. zmienne zadeklarowane jako „tablice asocjacyjne” (declare -A).

Są to typy zmiennych, które mogą być łatwiejsze (i wydajniej) przekazywane przez funkcje używając odniesień do nazw zamiast normalnego kopiowania, nawet jeśli nie przenoszą one ogromnych ilości danych.

Jeśli wszystkie te przykłady brzmią dziwnie i nadal niezrozumiale, to tylko dlatego, że odniesienia do nazw są rzeczywiście zaawansowany temat i rzadka potrzeba typowego scenariusza użycia B. popiół.

Mógłbym opowiedzieć o sytuacjach, w których znalazłem zastosowanie dla nazwisk w Bash, ale jak dotąd były one głównie dla dość „ezoterycznych” i skomplikowanych potrzeb. boję się, że gdybym je opisał, to tylko skomplikowałbym ci sprawę na tym etapie twojej nauki. Wystarczy wspomnieć o najmniej złożonym (i prawdopodobnie nie ezoterycznym): zwracaniu wartości z funkcji. Bash tak naprawdę nie obsługuje tej funkcjonalności, więc otrzymałem to samo, używając name-refs. Nawiasem mówiąc, jest to dokładnie to, co robi twój przykładowy kod.


Poza tym mała osobista rada, która lepiej pasowałaby do komentarza, ale nie jestem w stanie jej wystarczająco skondensować aby zmieścić się w granicach komentarzy StackExchange.

Myślę, że najwięcej w tej chwili powinieneś zrobić, to po prostu poeksperymentować z odniesieniami do nazw, używając prostych przykładów, które pokazałem, i być może z podanym przez Ciebie przykładowym kodem, pomijając na razie część „dlaczego na ziemi” i skupienie się tylko na części „jak to działa”. Trochę poeksperymentując, część „jak” może lepiej zagłębić się w twoim umyśle, tak że część „dlaczego” stanie się dla ciebie jasna we właściwym czasie, kiedy (lub czy) będziesz miał prawdziwy praktyczny problem, dla którego nazwa- ref naprawdę by się przydał.

Komentarze

  • LL3 Bardzo podoba mi się twoja odpowiedź i podoba mi się: wreszcie rozumiem, co deklaruje – – nie deklarowanie zmiennych, ale deklarowanie ich atrybutów; ale niestety straciłem orientację, kiedy zacząłeś wyjaśniać, czym jest referencja nazwy. Nie mam pojęcia, co robi i dlaczego go używać.
  • To znaczy – po co dawać ten atrybut
  • @JohnDoea widzę. Może po prostu zostawisz ten temat na chwilę. Prawdopodobnie jest zbyt wcześnie, aby uchwycić tę koncepcję na obecnym etapie nauki. W każdym razie rozszerzyłem moją odpowiedź o więcej przykładów, a także o mały osobisty dodatek dotyczący tego, jak moim zdaniem powinieneś postępować. Umieściłem również poziome linie, aby oddzielić ogólne wyjaśnienie declare od szczegółowego wyjaśnienia -n z załącznika osobistego. Dokonałem też trochę przeredagowania tu i tam, ale nie było to nic istotnego, więc myślę, że możesz po prostu ponownie przeczytać -n część wraz z małym dodatkiem.
  • Dziękuję, myślę, że ' w porządku, żebym się tego teraz nauczył. Potrzebuję tylko wyjaśnienia, które rozumiem, i powinienem ponownie przeczytać dzisiaj całą odpowiedź. ' jestem tutaj w pobliżu.
  • Wspominasz o foo="bar" i declare foo="bar" . Możesz wspomnieć (choćby w przypisie), że w funkcji powłoki declare foo="bar" tworzy zmienną lokalną i foo="bar" tworzy zmienna globalna.

Odpowiedź

Ogólnie declare w powłoka bash ustawia (lub usuwa lub wyświetla) atrybuty zmiennych. Atrybut to rodzaj adnotacji, która mówi „to jest odwołanie do nazwy”, „to jest tablica asocjacyjna”, „ta zmienna powinna zawsze być oceniana jako liczba całkowita” lub „ta zmienna jest tylko do odczytu i nie może być ponownie ustawionym „lub” ta zmienna jest eksportowana (zmienna środowiskowa) „itp.

Wbudowane typeset jest synonimem declare w bash, ponieważ typeset jest używany w innych powłokach (ksh, skąd pochodzi i na przykład zsh) do ustawiania atrybutów zmiennych.


Przyjrzyjmy się bliżej przykładowi odniesienia do nazwy w pytanie:

Funkcja powłoki, którą pokazujesz, z dodanym fragmentem kodu, który ją wykorzystuje:

#!/bin/bash function read_and_verify { read -p "Please enter value for "$1": " tmp1 read -p "Please repeat the value to verify: " tmp2 if [ "$tmp1" != "$tmp2" ]; then echo "Values unmatched. Please try again."; return 2 else declare -n ref="$1" ref=$tmp1 fi } read_and_verify foo printf "The variable "foo" has the value "%s"\n" "$foo" 

Uruchomienie tego:

 $ bash script.sh Please enter value for "foo": hello Please repeat the value to verify: hello? Values unmatched. Please try again. The variable "foo" has the value "" 

To pokazuje, że zmienna foo nie jest ustawiana na nic, gdy użytkownik wprowadzi dwa różne ciągi.

To pokazuje, że zmienna foo jest ustawiana na ciąg, który użytkownik wprowadził, gdy dwukrotnie wprowadzał ten sam ciąg .

Sposób, w jaki $foo pobiera wartość hello w głównej części skryptu, jest następujący: w funkcji powłoki:

declare -n ref="$1" ref=$tmp1 

gdzie $tmp1 to ciąg znaków hello wprowadzony przez użytkownika, a $1 to ciąg znaków foo przekazany do wiersza poleceń funkcji z głównej części

Zwróć uwagę, że zmienna ref została zadeklarowana z declare -n jako zmienną odniesienia do nazwy i że wartość foo jest podana jako wartość w tej deklaracji. Oznacza to, że od tego momentu, dopóki zmienna nie znajdzie się poza zakresem, użycie zmiennej ref będzie takie samo, jak użycie foo. Zmienna ref to zmienna odniesienia do nazwy odwołująca się do foo w tym momencie.

Powoduje to, że przypisanie wartości do ref, tak jak jest to zrobione w wierszu następującym po deklaracji, przypisze wartość do foo.

Wartość hello jest wtedy dostępna w $foo w głównej części skryptu.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *