Hvilke anvendelsesområder kan shellvariabler have?

Jeg løb lige ind i et problem, der viser mig, at jeg ikke er klar over omfanget af shellvariabler.

Jeg prøvede at brug bundle install, som er en Ruby-kommando, der bruger værdien af $GEM_HOME til at udføre sit arbejde. Jeg havde indstillet $GEM_HOME, men kommandoen ignorerede denne værdi, indtil jeg brugte export, som i export GEM_HOME=/some/path.

Jeg læste, at dette gør variablen på en eller anden måde “global” (også kendt som en miljøvariabel ), men jeg ved ikke forstå hvad det betyder. Jeg kender til globaler i programmering, men ikke på tværs af forskellige programmer.

Da min indstilling af sådanne variabler kun gælder for den aktuelle shell-session, hvordan kan jeg indstille dem til f.eks. En dæmoniseret proces?

Hvilke rækkevidde kan shellvariabler have?

Svar

Processerne er organiseret som et træ: hver proces har en unik forælder bortset fra init som PID er altid 1 og har ingen forælder.

Oprettelsen af en ny proces går generelt gennem et par fork / execv systemopkald, hvor miljøet i barneprocessen er en kopi af den overordnede proces.

For at placere en variabel i miljøet fra skallen skal du export denne variabel, så den er synlig rekursivt for alle børn. Men vær opmærksom på, at hvis et barn ændrer værdien af en variabel, er den ændrede værdi kun synlig for den, og alle processer oprettet efter den ændring (som en kopi som tidligere sagde).

Tag også højde for, at en underordnet proces kan ændre sit miljø, for eksempel kunne nulstille den til standardværdier, som det sandsynligvis gøres fra login for eksempel.

Kommentarer

  • Ah! OK, lad ‘ se, om jeg forstår dette. Hvis jeg siger FOO=bar i skallen, indstiller værdien for den aktuelle shell-proces. Hvis jeg derefter kører et program som (bundle install), der skaber en underordnet proces, som ikke ‘ t får adgang til FOO. Men hvis jeg havde sagt export FOO=bar, ville barneprocessen (og dens efterkommere) have adgang til den. En af dem kunne igen ringe til export FOO=buzz for at ændre værdien for sine efterkommere eller bare FOO=buzz for kun at ændre værdien for sig selv . Er det omtrent rigtigt?
  • @NathanLong At ‘ ikke er det nøjagtigt: i alle moderne skaller eksporteres en variabel enten (og altså er enhver ændring i værdi afspejles i efterkommernes miljø) eller ikke eksporteres (hvilket betyder, at variablen ikke er i miljøet). Især hvis variablen allerede er i miljøet, når skallen starter, eksporteres den.
  • Jeg var lidt forvirret af sætningen ” hvis et barn ændre værdien af en variabel, den ændrede værdi er kun synlig for den, og alle processer oprettet efter den ændring “. Det ville være mere korrekt at sige ” … synlig for den og alle dens efterfølgende processer oprettet efter den ændring ” – den anden børn af forældreprocessen, selv de der er startet efter barneprocessen, påvirkes ikke.

Svar

Kl. mindst under ksh og bash, kan variabler have tre rækkevidde, ikke to som alle resterende svar fortæller i øjeblikket.

I Ud over de eksporterede (dvs. miljø) variable og shell-ikke-eksporterede variable rækkevidde er der også en tredje smallere for funktionslokalvariabler.

Variabler erklæret i shell-funktioner med typeset token er kun synlig inde i de funktioner, de erklæres i, og i (under) funktioner kaldes derfra.

Denne ksh / bash kode:

# Create a shell script named /tmp/show that displays the scoped variables values. echo "echo [$environment] [$shell] [$local]" > /tmp/show chmod +x /tmp/show # Function local variable declaration function f { typeset local=three echo "in function": . /tmp/show } # Global variable declaration export environment=one # Unexported (i.e. local) variable declaration shell=two # Call the function that creates a function local variable and # display all three variable values from inside the function f # Display the three values from outside the function echo "in shell": . /tmp/show # Display the same values from a subshell echo "in subshell": /tmp/show # Display the same values from a disconnected shell (simulated here by a clean environment start) echo "in other shell" env -i /tmp/show 

producerer dette output:

in function: [one] [two] [three] in shell: [one] [two] [] in subshell: [one] [] [] in other shell [] [] [] 

Som du kan se, vises den eksporterede variabel fra de første tre placeringer, de ikke-eksporterede variabler vises ikke uden for den aktuelle skal, og funktionen lokal variabel har ingen værdi uden for selve funktionen. Den sidste test viser slet ingen værdier, det skyldes, at eksporterede variabler ikke deles mellem skaller, dvs. de kan kun nedarves, og den arvede værdi kan ikke påvirkes bagefter af den overordnede shell.

Bemærk, at denne sidstnævnte adfærd er helt forskellig fra Windows, hvor du kan bruge systemvariabler, der er fuldt ud globale og deles af alle processer.

Svar

De er omfattet af processen

De andre svarere hjalp mig med at forstå, at shell-variabelt omfang handler om processer og deres efterkommere .

Når du skriver en kommando som ls på kommandolinjen, er du faktisk forking en proces til at køre ls -programmet. Den nye proces har din shell som overordnet.

Enhver proces kan have sine egne “lokale” variabler, som er ikke videregivet til underordnede processer. Det kan også indstille “miljø” -variabler, som er. Brug af export skaber en miljøvariabel. I begge I tilfælde, vil ikke-relaterede processer (originaler fra hinanden) ikke se variablen; vi kontrollerer kun det barn, der indkøber esses se.

Antag at du har en bash shell, som vi “kalder A. Du skriver bash , der skaber en underordnet proces bash shell, som vi “kalder B. Alt, hvad du kaldte export på i A, vil stadig blive indstillet i B.

Nu, i B siger du FOO=b. En af to ting vil ske:

  • Hvis B ikke modtog (fra A) en miljøvariabel kaldet FOO, oprettes en lokal variabel. Børn af B får ikke det (medmindre B kalder export).
  • Hvis B gjorde modtager (fra A) en miljøvariabel kaldet FOO, den ændrer den for sig selv og dens efterfølgende forked børn . Børn af B vil se den værdi, som B tildelte. dette påvirker dog slet ikke A.

Her “er en hurtig demo .

FOO=a # set "local" environment variable echo $FOO # "a" bash # forks a child process for the new shell echo $FOO # not set exit # return to original shell echo $FOO # still "a" export FOO # make FOO an environment variable bash # fork a new "child" shell echo $FOO # outputs "a" FOO=b # modifies environment (not local) variable bash # fork "grandchild" shell echo $FOO # outputs "b" exit # back to child shell exit # back to original shell echo $FOO # outputs "a" 

Alt dette forklarer mit oprindelige problem: Jeg satte GEM_HOME i min skal, men da jeg ringede bundle install, der skabte en underordnet proces. Fordi jeg ikke havde brugt export, modtog underordnede processen ikke shell “s GEM_HOME.

Fjernelse af eksport

Du kan “fjerne eksport” til en variabel – forhindre, at den overføres til børn – ved hjælp af export -n FOO.

export FOO=a # Set environment variable bash # fork a shell echo $FOO # outputs "a" export -n FOO # remove environment var for children bash # fork a shell echo $FOO # Not set exit # back up a level echo $FOO # outputs "a" - still a local variable 

Kommentarer

  • Når du siger ” det vil ændre det for sig selv og dets børn ” du skal præcisere, at kun børn oprettede efter ændringen vil se den ændrede værdi.
  • @enzotib – godt punkt. Opdateret.

Svar

Den bedste forklaring, jeg kan finde på eksport, er denne:

http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html

Variablen, der er angivet i en subshell eller underordnet shell, er kun synlig for den subshell, hvor den er defineret. Den eksporterede variabel er faktisk lavet til at være en miljøvariabel. For at være klar udfører din bundle install sin egen shell, som ikke ser $GEM_HOME, medmindre den er lavet til en environment variabel aka eksporteret.

Du kan se på dokumentationen til variabelt omfang her:

http://www.tldp.org/LDP/abs/html/subshells.html

Kommentarer

  • Ah, så jeg var forkert at bruge udtrykket ” miljøvariabel ” til FOO=bar; du skal bruge export for at gøre det til et. Spørgsmål rettet i overensstemmelse hermed.
  • Se på det link, jeg har tilføjet.

Svar

Der er som forventet et hierarki af variable rækkevidde.

Miljø

Det yderste omfang er miljøet. Dette er det eneste omfang styres af operativsystemet og er derfor garanteret at eksistere for hver proces. Når en proces startes, modtager den en kopi af forældrenes miljø, hvorefter de to bliver uafhængige: ændring af barnets miljø ændrer ikke forældrenes miljø, og ændring af forældrenes miljø ændrer ikke miljøet for et allerede eksisterende barn.

Shell-variabler

Skaller har deres egen forestilling om variabler. Det er her, tingene begynder at blive lidt forvirrende.

Når du tildeler en værdi til en variabel i en shell, og den variablen allerede findes i miljøet, modtager miljøvariablen den nye værdi. Men hvis variablen ikke er i miljøet, bliver den dog en shell variabel. Shell-variabler findes kun i shell-processen, svarende til hvordan Ruby-variabler kun findes i et Ruby-script. De arves aldrig af barneprocesser.

Her er hvor export nøgleordet kommer til spil. Det kopierer en shellvariabel til shell-processens miljø, hvilket gør det muligt for barneprocesser at arve.

Lokale variabler

Lokale variabler er shellvariabler, der er omfattet af kodeblokkene, der indeholder dem. Du erklærer lokale variabler med typeset nøgleordet (bærbart) eller local eller declare (Bash ). Som andre shellvariabler arves ikke lokale variabler af underordnede processer. Lokale variabler kan heller ikke eksporteres.

Skriv et svar

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