Hvad er “ erklærer ” i Bash?

Efter at have læst ilkkachus svar på dette spørgsmål lærte jeg om eksistensen af declare (med argument -n) indbygget skal.

help declare bringer:

Indstil variabelværdier og attributter.

Erklær variabler, og giv dem attributter. Hvis der ikke er angivet NAVNE, skal du vise attributter og værdier for alle variabler.

-n … gør NAME til en reference til den variabel, der er navngivet efter dens værdi

I bede om en generel forklaring med et eksempel på declare fordi jeg ikke forstår man. Jeg ved hvad der er en variabel og udvider den, men jeg savner stadig mandeclare (variabel attribut?).

Måske vil du gerne forklare dette baseret på koden af ilkkachu i svaret:

#!/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 } 

Kommentarer

Svar

I de fleste tilfælde er det nok med en implicit erklæring i bash

asdf="some text" 

Men nogle gange vil du have, at en variabels værdi kun skal være heltal (så hvis den senere ændres, selv automatisk, kunne den kun ændres til et heltal, er som standard nul i nogle tilfælde) og kan bruge:

declare -i num 

eller

declare -i num=15 

Nogle gange vil du have arrays, og så har du brug for declare

declare -a asdf # indexed type 

eller

Du kan finde gode tutorials om arrays i bash når du surfer på internettet med søgestrengen” bash array tutorial “(uden anførselstegn), til eksempel

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


Jeg synes, det er de mest almindelige tilfælde, når du erklærer variabler.


Vær også opmærksom på, at

  • i en funktion, declare gør variablen lokal (i funktionen)
  • uden noget navn, den viser alle variabler (i den aktive skal)

    declare 

Endelig får du en kort oversigt over funktionerne i shell-indbygget kommando declare i bash med kommandoen

help declare 

Kommentarer

  • Hej fra OP! Jeg synes, dit svar er fantastisk, og jeg har opstemt det og tak for dette, efter min mening, et meget didaktisk svar. Jeg har netop foreslået en mindre redigering, der efter min ydmyge mening gør det endnu lettere og tilgængeligt for nybegyndere at læse; Venligst gå igennem dette forslag.
  • Jeg så lige, at user:muru stemte for at afvise redigering; vær venlig at vide, at jeg og muru har ” sammenstød med ” flere gange i de forskellige sektioner på dette websted, og jeg antager, at hans afvisning ikke er ‘ t-mål og er faktisk skadelig i modsætning til de direkte ændringer, der vises på siden med redigeringsforslag her: unix.stackexchange.com/review/suggested -edits / 325749
  • @JohnDoea, jeg så, at også en anden bruger har afvist dine redigeringer. Jeg synes, nogle af dine redigeringer er gode, men nogle af dem vil ændre meddelelsen fra det, jeg havde tænkt mig, så jeg ville ikke lide dem. Jeg kan redigere svaret, så det inkluderer gode redigeringer.
  • tak; som du sikkert ved, er afvisning af redigeringer langt mere almindelig i SE end at acceptere dem (selv delvis); tak for at have fortalt mig, at en anden bruger afviste redigeringen (jeg så ‘ ikke ærligt før) og for at overveje at indsætte mindst nogle af mine redigeringer i dit svar; Jeg respekterer dette meget,

Svar

Outputtet fra help declare er ret kort. En klarere forklaring kan findes i man bash eller info bash – sidstnævnte er kilden til det følgende.

For det første nogle definitioner. Om variabler og attributter :

En parameter er en enhed, der gemmer værdier. … En variabel er en parameter betegnet med en name. En variabel har en værdi og nul eller flere attributter . Attributter tildeles ved hjælp af declare indbygget kommando …

Og om declare indbygget :

declare

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

Erklær variabler og giv dem attributter. Hvis der ikke er angivet nogen navne, skal du vise værdierne for variabler i stedet.

-n
Giv hver navn attributten nameref , hvilket gør det til en navnehenvisning til en anden variabel. Den anden variabel er defineret af værdien af navn . Alle referencer, tildelinger og attributændringer til navn undtagen dem, der bruger eller ændrer -n selve attributten, udføres på den variabel, der henvises til af navn s værdi. …

Bemærk, at navnehenvisning variabler kun er tilgængelige i Bash 4.3 eller nyere 1 .

Også for en nyttig introduktion til declare og variable attributter i Bash vil jeg henvise dig til dette svar på ” Hvad gør declare name og declare -g? ” (som dog hovedsagelig fokuserer på variabler).


Dybest set 2 , declare name=[value] svarer til opgaven name=[value], som du sandsynligvis er fortrolig med. I begge tilfælde tildeles name nullen værdi, hvis value mangler.

Bemærk, at den lidt forskellige declare name i stedet ikke indstiller variablen 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  

Variablen name kan således være:

  • erklæret og unset efter declare name;
  • erklæret og sæt med null som værdi efter name= eller declare name=;
  • erklæret , sæt og med en værdi ikke nul efter name=value eller .

Mere generelt opretter declare [options] name=value

  1. variablen name – hvilket er en parameter med et navn, som igen kun er en del af hukommelsen, du kan bruge til at gemme information 4 ;
  2. tildeler værdien value til den;
  3. indstiller valgfrit name “s attributter, som definerer både typen af værdi det kan gemme (ikke i form af en type strengt taget, da Bash s sprog ikke er skrevet) og måder det kan manipuleres på.

Attributter er sandsynligvis lettere at forklare med et eksempel: ved hjælp af declare -i name indstilles ” heltal ” af name, så det kan behandles som et heltal; citerer manual , ” aritmetisk evaluering udføres, når variablen er tildelt en værdi “:

 ## 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  

I lyset af ovenstående, hvad der sker i ilkkachus kode, er at:

  1. En variabel med navnet ref erklæres med ” nameref ” attributsæt, og indholdet af $1 (det første positionelle argument) tildeles det:

     declare -n ref="$1"  

    Målet med en navnehenvisningsvariabel såsom ref er at holde navnet på en anden variabel, som generelt ikke ville være kendt på forhånd, muligvis fordi vi ønsker, at den skal defineres dynamisk (f.eks. Fordi vi vil genbruge et stykke kode og have det anvendt på flere variabler) og på giver en bekvem måde at henvise til (og manipulere) den. (Dog ikke den eneste: indirektion er et alternativ; se Udvidelse af shellparameter ).

  2. Hvornår værdien af variablen tmp1 tildeles ref:

     ref=$tmp1  

    en yderligere variabel, hvis navn er værdien af ref, erklæres implicit. Værdien af tmp1 tildeles også indirekte til den implicit erklærede variabel ved hjælp af denne eksplicitte tildeling til ref .

I sammenhæng med er dit linkede spørgsmål ved at ringe til read_and_verify som

 read_and_verify domain "Prompt text here..."  

vil erklære variablen domain og tildel det værdien af tmp1 (dvs. brugerens input). Det er nøjagtigt designet til at genbruge koden, der interagerer med brugeren og udnytte en navne-variabel at erklære domain og et par andre variabler.

For at se nærmere på den implicitte del kan vi gengive processen trin for trin:

 ## 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 Reference: ÆNDRINGER fil, sektion ” 3. Nye funktioner i Bash “, punkt ” w “.
Dette kan være relevant: for eksempel CentOS Linux 7.6 (i øjeblikket seneste version) leveres med Bash 4.2 .

2 Som normalt med shell builtins, en udtømmende og kortfattet forklaring er undvigende, da de udfører forskellige, muligvis heterogene handlinger. Jeg vil fokusere på kun at erklære, tildele og indstille attributter, og jeg vil overveje at liste, scope og fjerne attributter uden for dette svar.

3 Denne opførsel af declare -p er blevet introduceret i Bash 4.4. Reference: ÆNDRINGER fil, sektion ” 3. Nye funktioner i Bash “, punkt ” f “.
Som G-Man påpegede i kommentarer, i Bash 4.3 declare name; declare -p name giver en fejl. Men du kan stadig kontrollere, at name findes med declare -p | grep "declare -- name".

4 FullBashGuide, Parametre på mywiki.wooledge.org

Kommentarer

  • (1) Jeg kan ikke gengive de resultater, du viser i din første kodeblok: declare name efterfulgt af declare -p name giver “bash: declare: name: not found”. (Selvom declare -p | grep na giver declare -- name.) (2) Jeg mener, at det er lidt vildledende at præsentere echo "${name-isunset}" i sammenhæng med declare name, for så vidt som den behandler en udeklareret (dvs. udefineret) variabel det samme som en erklæret men frakoblet variabel. (3) Du vil måske nævne, at navneefter kun er tilgængelige i bash version 4.3 og nyere.
  • @ G-Man Tak for dine bemærkninger! Jeg ‘ adresserer dem så snart jeg kan, og jeg ‘ opdaterer mit svar, hvor det er relevant. Hvad angår (1), giver min GNU bash, version 5.0.7(1)-release (x86_64-pc-linux-gnu) på Arch Linux stadig de resultater, jeg viste. Måske er den adfærd først blevet introduceret for nylig. Jeg ‘ undersøger det.
  • Yeah; Jeg ‘ bruger kun version 4.3.
  • @ G-Man Svar opdateret med noter om (1) og (3). Om (2): Jeg havde til formål at illustrere, at declare x ikke ‘ t indstillede x, mens declare x= gør det. Jeg kunne ikke ‘ ikke finde nogen henvisning til at hævde påstanden om, at declare -- x (som output af declare -p x) betyder ” ikke indstillet “, mens declare -- x="" betyder ” sæt “; således bragte jeg ${parameter-word} udvidelsen, selvom den ikke kan skelne mellem ” unset ” og ” findes ‘ t “, som du påpeger. Jeg ‘ er dog ikke sikker på, hvordan jeg kan afklare dette i mit svar (uden at distrahere læseren fra punktet).

Svar

Jeg vil prøve at forklare dette, men tilgiv mig, hvis jeg ikke følger det eksempel, du gav. Jeg vil hellere prøve at guide dig ad min egen, anderledes tilgang.

Du siger, at du allerede forstår begreber som “variabler” og “udvidelse” osv. baggrundsviden, der ellers ville kræve dybere fokus.

Så jeg begynder med at sige, at det højst grundlæggende niveau, kommandoen declare er bare en måde for dig at fortælle Bash, at du har brug for en variabel værdi (dvs. en værdi, som muligvis ændres under scriptudførelse), og at du vil henvis til den værdi ved hjælp af et specifikt navn, netop det navn, du angiver ud for selve kommandoen declare.

Det vil sige:

 declare foo="bar"  

fortæller Bash, at du vil have variablen med navnet foo have værdien bar.

Men .. vent et øjeblik .. vi kan gør det uden at bruge declare overhovedet, kan vi ikke. Som i:

 foo="bar"  

Meget sandt.

Nå , sker det således, at ovenstående enkle tildeling faktisk er en implicit måde til .. faktisk .. at erklære en variabel.

( Det sker også, at ovenstående er en af et par måder at skift værdien af variablen foo; faktisk er den nøjagtigt den mest direkte, kortfattet, tydelig, ligefrem måde .. men det er ikke den eneste .. .. Jeg kommer tilbage til dette senere .. ).

Men så hvis det er sådan godt muligt at erklære et “navn, der vil mærke variabelværdier” (bare “variabel” herfra for kortfattethed) uden at bruge declare overhovedet, hvorfor vil du nogensinde Brug denne pompøse “erklær” -kommando?

Svaret ligger i, at ovenstående implici t måde at erklære en variabel på (foo="bar"), det .. implicit .. får Bash til at overveje, at variablen er af den type, der oftest bruges i det typiske brugsscenarie for en shell .

En sådan type er strengetypen, dvs. en række tegn uden særlig betydning. Derfor er en streng, hvad du får, når du bruger den implicitte erklæring.

Men du, som programmør, er undertiden nødt til at overveje en variabel som f.eks. Et tal .. som du har brug for at regne operationer .. og ved hjælp af en implicit erklæring som foo=5+6 vil ikke få Bash til at tildele værdi 11 til foo som kunne du forvente. Det tildeler snarere foo sekvensen af de tre tegn 5 + 6.

Så .. du har brug for en måde at fortælle Bash at du vil have foo til at blive betragtet som et tal, ikke et streng .. og det er, hvad en eksplicit declare er nyttig til.

Sig bare:

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

og Bash gør med glæde matematikken for dig og tildeler værdien numerisk 11 til variablen foo.

Det vil sige: ved at sige declare -i foo giver du variablen foo attribut for at være et heltal.

Erklæring af tal (præcist heltal, fordi Bash stadig ikke forstår decimaler, flydende punkter og alt det der), kan være den første grund til at bruge declare, men det er ikke den eneste grund. Som du allerede har forstået, er der et par andre attributter, du kan give variabler. For eksempel kan du have Bash til altid at gøre en variabel med store bogstaver, uanset hvad: hvis du siger declare -u foo, så når du siger foo=bar Bash tildeler faktisk strengen BAR til variablen foo.

For at give nogen af disse attributter til en variabel skal du skal bruge kommandoen declare, der er intet andet valg.


Nu, en anden af attributter, du kan give gennem declare, er den berygtede “name-ref” -attribut, -n -attributten. ( Og nu vil jeg genoptage det koncept, jeg lagde på vent tidligere ).

Navnet-ref-attributten giver grundlæggende Bash-programmører mulighed for at ændre værdien af en variabel. Det giver mere præcist en indirekte måde at gøre det på.

Her er hvordan det virker:

Du declare en variabel, der har attributten -n, og det er meget anbefales (dog ikke strengt krævet, men det gør tingene enklere) at du også giver en værdi til dette meget variabel på den samme declare kommando. Sådan:

 declare -n baz="foo"  

Dette fortæller Bash, at fra da til, hver gang du bruger eller ændrer værdien af variablen med navnet baz, skal den faktisk bruge eller ændre værdien af variablen med navnet foo.

Hvilket betyder, at fra da af, yo du kan sige noget som baz=10+3 for at få foo til at få værdien 13.Antager naturligvis, at foo tidligere blev erklæret som heltal (declare -i) som vi gjorde for et minut siden, ellers får den sekvensen af de fire tegn 1 0 + 3.

Også: hvis du ændrer foo s værdi direkte, som i foo=15, vil du se 15 også ved at sige echo “${baz}”. Dette skyldes, at variabel baz erklæret som navn-ref af foo altid afspejler foo s værdi.

Ovenstående declare -n kommando siges at være en “navn-reference”, fordi den gør variabel baz henvis til navnet på en anden variabel. Faktisk har vi erklæret, at baz har værdien “foo”, som på grund af -n -muligheden håndteres af Bash som navnet på en anden variabel.

Nu, hvorfor på jorden ville du nogensinde ønske at gøre det?

Nå .. det er værd at sige, at dette er en funktion til ganske avancerede behov.

Faktisk så avanceret, at når en programmør står over for et problem, der virkelig kræver et navn-ref, er det også sandsynligvis at et sådant problem snarere skal adresseres til ved hjælp af et korrekt programmeringssprog i stedet for Bash.

Et af disse avancerede behov er for eksempel når du som programmør ikke kan vide under udvikling hvilken variabel du skal bruge i et bestemt punkt i et script, men det vil være fuldt kendt dynamisk ved kørselstid. Og i betragtning af at der ikke er nogen måde for enhver programmør at gribe ind i løbetid, er den eneste mulighed at sørge for på forhånd for en sådan situation i scriptet, og en “name-ref” kan være den eneste levedygtige vej. Som et udbredt kendskab til dette avancerede behov, så tænk f.eks. På plug-ins. Programmøren af et “plugin-kompatibelt” program skal på forhånd sørge for generiske bestemmelser for fremtidige (og muligvis tredjeparts) plug-ins. Derfor bliver programmøren nødt til at bruge faciliteter som et navn-ref i Bash.

Et andet avanceret behov er, når du skal håndtere enorme mængder data i RAM og du også har brug for at videregive disse data omkring funktioner i dit script, som også skal ændre disse data undervejs. I et sådant tilfælde kunne du bestemt kopiere disse data fra en funktion til en anden (som Bash gør, når du gør dest_var="${src_var}", eller når du påberåber funktioner som i myfunc "${src_var}"), men hvis de data er enorme, ville det give et enormt spild af RAM og til en meget ineffektiv operation. Så løsningen, hvis der opstår sådanne situationer, er ikke at bruge en kopi af dataene, men en henvisning til disse data. I Bash, et navn-ref. Denne brugssag er virkelig normen i ethvert moderne programmeringssprog, men det er ganske usædvanligt, når det kommer til Bash, fordi Bash for det meste er designet til korte enkle scripts, der for det meste beskæftiger sig med filer og eksterne kommandoer, og Bash-scripts skal derfor sjældent passere enorm mængde data mellem funktioner. Og når et scripts funktioner behøver at dele nogle data (få adgang til det og ændre det) opnås dette normalt ved bare at bruge en global variabel, hvilket er helt normen i Bash-scripts så meget som det er meget udfaset i korrekte programmeringssprog.

Så kan der være en bemærkelsesværdig brugssag for navne-ref i Bash, og (måske ironisk nok) er det knyttet til, når du bruger endnu andre typer variabler:

  1. variabler, der erklæres som “indekserede arrays” (declare -a)
  2. variabler, der erklæres som “associerende arrays” (declare -A).

Dette er en type variabler, der kan lettere (såvel som mere effektivt) sendes langs funktioner ved at bruge navne-ref i stedet for ved normal kopiering, selv når de ikke har store mængder data.

Hvis alle disse eksempler lyder underligt og stadig uforståeligt, er det kun fordi navne-ref faktisk er et avanceret emne og et sjældent behov for det typiske brugsscenarie for B aske.

Jeg kunne fortælle dig om lejligheder, hvor jeg for eksempel har fundet brug for navne-refs i Bash, men hidtil har de hovedsagelig været til ganske “esoteriske” og komplicerede behov, og jeg er bange for, at hvis jeg beskrev dem, ville jeg kun komplicere tingene for dig på dette tidspunkt af din læring. Bare for at nævne det mindst komplekse (og muligvis ikke esoteriske): returnering af værdier fra funktioner. Bash understøtter ikke rigtig denne funktionalitet, så jeg opnåede det samme ved at bruge navn-ref. Dette er i øvrigt nøjagtigt, hvad din eksempelkode gør.


Udover dette, en lille personlig rådgivning, som faktisk ville være bedre egnet til en kommentar, men jeg har ikke været i stand til at kondensere det nok at passe ind i StackExchanges kommentar grænser.

Jeg synes, at det mest du skal gøre i øjeblikket, er bare at eksperimentere med navne-ref ved at bruge de enkle eksempler, jeg viste, og måske med den eksempelkode, du gav, uden at se for øjeblikket “hvorfor i alverden” del og kun fokusere på “hvordan det fungerer” del. Ved at eksperimentere lidt kan “hvordan” -delen synke bedre ind i dit sind, så “hvorfor” -delen vil komme tydeligt frem til dig, når (eller hvis) du har et reelt praktisk problem, som et navn- ref ville virkelig komme godt med.

Kommentarer

  • LL3 Jeg kan godt lide dit svar, og jeg tommelfinger op: Jeg forstår endelig, hvad erklæringen gør – – ikke deklarere variabler, men deklarere deres attributter; men desværre mistede jeg sporet, da du begyndte at forklare, hvad der er en navne-ref. Jeg fik ingen idé om, hvad det gør, og hvorfor jeg skulle bruge det.
  • Det er – hvorfor skulle man give denne attribut
  • @JohnDoea ser jeg. Måske forlader du måske dette emne for øjeblikket. Det er sandsynligvis for tidligt at forstå dette koncept på det aktuelle tidspunkt for din læring. Under alle omstændigheder har jeg udvidet mit svar med flere eksempler og også et lille personligt tillæg til, hvordan jeg synes, du skal gå videre. Jeg har også sat vandrette linjer for at afgrænse den generelle forklaring af declare fra den specifikke forklaring af -n fra det personlige tillæg. Jeg har også lavet en smule omformulering her og der, men intet væsentligt, så jeg tror, du kan bare genlæse -n -delen plus det lille tillæg.
  • Tak, jeg synes, det ‘ er okay for mig at lære om dette lige nu, jeg har bare brug for en forklaring, jeg kan forstå, og jeg bør genlæse hele dit svar i dag, jeg ‘ her omkring.
  • Du nævner foo="bar" og declare foo="bar" . Det kan være en god idé at nævne (hvis kun i en fodnote), at declare foo="bar" i en shell-funktion opretter en lokal variabel og foo="bar" opretter en global variabel.

Svar

Generelt declare i bash shell sæt (eller fjerner eller viser) attributter på variabler. En attribut er en slags kommentar, der siger “dette er en navnehenvisning” eller “dette er et associerende array”, eller “denne variabel skal altid evalueres som et heltal”, eller “denne variabel er skrivebeskyttet og kan ikke genindstilles “, eller” denne variabel eksporteres (en miljøvariabel) “osv.

Den indbyggede typeset er et synonym for declare i bash, da typeset bruges i andre skaller (ksh, hvor den stammer fra, og zsh for eksempel) til indstilling af variable attributter.


Se nærmere på eksemplet på navnehenvisningen i spørgsmålet:

Den skalfunktion, du viser, med en ekstra kode kode, der bruger den:

#!/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" 

Kører dette:

 $ 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 "" 

Det viser, at foo variablen ikke indstilles til noget, når brugeren indtaster to forskellige strenge.

Det viser, at variablen foo bliver indstillet til den streng, som brugeren indtastede, da de indtastede den samme streng to gange .

Den måde, som $foo får værdien hello i hoveddelen af scriptet, er ved følgende linjer i shell-funktionen:

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

hvor $tmp1 er strengen hello indtastet af brugeren, og $1 er strengen foo sendt ind på funktionens kommandolinje fra hoveddelen af script.

Bemærk, at ref -variablen erklæres med declare -n som en navnehenvisningsvariabel, og at værdien foo angives som værdien i denne erklæring. Dette betyder, at fra det tidspunkt, indtil variablen passerer uden for rækkevidde, vil enhver brug af variablen ref være den samme som at bruge foo. Variablen ref er en navnehenvisningsvariabel der henviser til foo på dette tidspunkt.

Dette har den konsekvens, at tildeling af en værdi til ref, som det sker på linjen efter erklæringen, tildeler værdien til foo.

Værdien hello er derefter tilgængelig i $foo i hoveddelen af scriptet.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *