Mitä laajuuksia shell-muuttujilla voi olla?

Juuri törmäsin ongelmaan, joka osoittaa minulle, etten ole selvillä shell-muuttujien laajuudesta.

Yritin käytä bundle install, joka on Ruby-komento, joka käyttää työnsä $GEM_HOME arvoa. Olin asettanut $GEM_HOME, mutta komento jättää kyseisen arvon huomiotta, kunnes käytin export -tunnistetta, kuten kohdassa export GEM_HOME=/some/path.

Luin, että tämä tekee muuttujasta jotenkin ”globaalin” (tunnetaan myös nimellä ympäristömuuttuja ), mutta en t ymmärrä mitä se tarkoittaa. Tiedän globaaleista ohjelmoinnista, mutta en eri ohjelmista.

Koska asetan tällaiset muuttujat koskemaan vain nykyistä shell-istuntoa, kuinka asetan ne esimerkiksi demonisoituun prosessiin?

Mitä laajuuksia shell-muuttujilla voi olla?

Vastaa

Prosessit on järjestetty puuksi: jokaisella prosessilla on yksilöllinen ylätaso lukuun ottamatta init, joka PID on aina 1 eikä sillä ole vanhempaa.

Uuden prosessin luominen tapahtuu yleensä parin fork / execv -järjestelmäkutsut, joissa lapsiprosessin ympäristö on vanhempien prosessin kopio .

Jotta muuttuja voidaan sijoittaa ympäristöön kuoresta, sinun on export muuttuja, jotta se näkyy rekursiivisesti kaikille lapsille. Mutta ole tietoinen siitä, että jos lapsi muuttaa muuttujan arvoa, muutettu arvo näkyy vain hänelle ja kaikki muutoksen jälkeen luodut prosessit (ollessa kopio , kuten aiemmin

Ota huomioon myös, että lapsiprosessi voi muuttaa ympäristöään, esimerkiksi palauttaa sen oletusarvoihin, kuten luultavasti tehdään kohdasta login esimerkki.

Kommentit

  • Ah! OK, anna ’ s nähdä, ymmärränkö tämän. Jos sanon kuoressa FOO=bar, se asettaa nykyisen kuoriprosessin arvon. Jos suoritan sitten ohjelman, kuten (bundle install), se luo aliprosessin, joka ’ ei pääse FOO. Mutta jos olisin sanonut export FOO=bar, lapsiprosessilla (ja sen jälkeläisillä) olisi pääsy siihen. Yksi heistä voisi puolestaan kutsua export FOO=buzz muuttamaan jälkeläistensa arvoa tai vain FOO=buzz muuttamaan arvoa vain itselleen . Onko se totta?
  • @NathanLong Että ’ ei ole aivan oikein: kaikissa nykyaikaisissa kuoreissa muuttuja joko viedään (ja siten kaikki arvon muutokset ovat heijastuu jälkeläisten ympäristöön) tai ei viedä (eli muuttuja ei ole ympäristössä). Erityisesti, jos muuttuja on jo ympäristössä kuoren alkaessa, se viedään.
  • Olin hieman hämmentynyt lauseesta ”, jos lapsi Jos muutat muuttujan arvoa, muutettu arvo näkyy vain sille ja kaikki sen jälkeen luodut prosessit muuttuvat ”. Olisi oikeampi sanoa ” … sille näkyvä ja kaikki sen muutoksen jälkeen luodut jälkeläisprosessit ” – toinen Vanhemman prosessin lapsiin, myös lapsiprosessin jälkeen aloitettuihin, ei ole vaikutusta.

Vastaa

Klo vähiten kohdissa ksh ja bash, muuttujilla voi olla kolme -piirit, ei kaksi , kuten kaikki jäljellä olevat vastaukset kertovat.

vietyjen (eli ympäristö) muuttujien ja kuorien viemättömien muuttujien laajuuksien lisäksi on myös kolmas kapeampi funktion paikallisille muuttujille.

Kuoritoiminnoissa ilmoitetut muuttujat typeset -tunnus on näkyvissä vain niiden toimintojen sisällä, joihin ne on ilmoitettu, ja sieltä soitetuissa (ala) toiminnoissa.

Tämä ksh / bash -koodi:

# 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 

tuottaa tämän tuotoksen:

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

Kuten näette, viety muuttuja näytetään kolmesta ensimmäisestä sijainnista, viemättömiä muuttujia ei näytetä nykyisen kuoren ulkopuolella ja funktiolla paikallinen muuttuja ei ole arvoa itse toiminnon ulkopuolella. Viimeinen testi ei näytä arvoja ollenkaan, koska vietyjä muuttujia ei jaeta kuorien välillä, ts. Ne voidaan periä vain, eikä vanhempi kuori voi vaikuttaa perittyyn arvoon jälkikäteen.

Huomaa, että tämä jälkimmäinen käyttäytyminen poikkeaa melko hyvin Windowsista, jossa voit käyttää järjestelmämuuttujia, jotka ovat täysin globaaleja ja jakavat kaikki prosessit.

Vastaa

Ne kuuluvat prosessin piiriin.

Muut vastaajat auttoivat minua ymmärtämään, että kuoren muuttujan laajuus koskee ja heidän jälkeläisensä .

Kun kirjoitat komentoriville komennon kuten ls, olet todella haastaa prosessin ls -ohjelman ajamiseksi. Uudella prosessilla on komentotulkkisi.

Jokaisella prosessilla voi olla omat paikalliset muuttujansa, jotka ovat ei välitetä aliprosesseihin. Se voi myös asettaa ”ympäristömuuttujia”, jotka ovat. export -toiminnon avulla luodaan ympäristömuuttuja. Tällöin etuyhteydettömät prosessit (alkuperäisen ikäisensä) eivät näe muuttujaa; hallitsemme vain sitä, mikä lapsiprok esseitä.

Oletetaan, että sinulla on bash-kuori, jota kutsumme A: ksi. Kirjoitat bash , joka luo aliprosessin bash-kuoren, jota kutsumme B: ksi. Kaikki, mitä kutsuit export A: ssa, asetetaan edelleen B: hen.

Nyt, B: ssä sanot FOO=b. Yksi kahdesta asiasta tapahtuu:

  • Jos B ei saanut (A: lta) ympäristömuuttujaa nimeltä FOO, se luo paikallisen muuttujan. B: n lapset eivät saa sitä (ellei B kutsu export).
  • Jos B ei saa (A: lta) ympäristömuuttujan, jota kutsutaan FOO, se muokkaa sitä itse ja sen myöhemmin haarautuneet lapset . B: n lapset näkevät arvon, jonka B antoi. tämä ei kuitenkaan vaikuta lainkaan A: han.

Tässä ”nopea esittely .

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" 

Kaikki tämä selittää alkuperäisen ongelmani: asetin GEM_HOME komentotulkkiini, mutta kun soitin bundle install, joka loi lapsiprosessin. Koska en ollut käyttänyt export, lapsiprosessi ei saanut kuorta ”s GEM_HOME.

Viennin poistaminen

Voit ”poistaa” muuttujan – estää sen siirtymisen lapsille – käyttämällä 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 

Kommentit

  • Kun sanot ” se muuttaa sitä itselleen ja lapsilleen ” sinun tulisi selventää, että vain lapset loivat muokkauksen jälkeen näkee muokatun arvon.
  • @enzotib – hyvä asia. Päivitetty.

Vastaus

Paras selitys vientiin on tämä:

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

Ali- tai alikuoren muuttujajoukko näkyy vain alakuori, jossa se on määritelty. Viedystä muuttujasta tehdään itse asiassa ympäristömuuttuja. Joten selväksi bundle install suorittaa oman kuorensa, joka ei näe $GEM_HOME, ellei siitä ole tehty environment muuttuja eli viety.

Voit katsoa muuttujan laajuuden dokumentaatiota täältä:

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

Kommentit

  • Ah, joten käytin väärin termiä ” ympäristömuuttuja ” kohteelle FOO=bar; sinun on käytettävä export tehdä siitä yhden. Kysymys korjattu vastaavasti.
  • Katsokaa linkkiä, johon olen lisännyt.

Vastaa

Muuttujien laajuuksien hierarkia on odotetusti.

Ympäristö

Uloin ulottuvuus on ympäristö. Tämä on ainoa laajuus käyttöjärjestelmän hallitsema ja sen takia on olemassa jokaiselle prosessille. Kun prosessi aloitetaan, se saa a kopio vanhemman ympäristöstä, jonka jälkeen molemmat itsenäistyvät: lapsen ympäristön muokkaaminen ei muuta vanhemman ympäristöä eikä vanhemman ympäristön muuttaminen jo olemassa olevan lapsen ympäristöä.

Kuorimuuttujat

Kuorilla on oma käsitys muuttujista. Tällöin asiat alkavat tulla hieman hämmentäviksi.

Kun määrität arvon muuttujalle kuoressa ja kyseinen muuttuja on jo ympäristössä, ympäristömuuttuja saa uuden arvon. Jos muuttuja ei kuitenkaan vielä ole ympäristössä, siitä tulee shell -muuttuja. Shell-muuttujat ovat olemassa vain shell-prosessissa, samalla tavalla kuin Ruby-muuttujat ovat vain Ruby-komentosarjassa. Lapsiprosessit eivät koskaan peri niitä.

Tässä tulee näkyviin avainsana export. Se kopioi kuorimuuttujan kuoriprosessin ympäristöön, jolloin aliprosessit voivat periä.

Paikalliset muuttujat

Paikalliset muuttujat ovat kuorimuuttujia, jotka on rajattu niitä sisältäviin koodilohkoihin. Ilmoitat paikalliset muuttujat avainsanalla typeset (kannettava) tai local tai declare (Bash ). Muiden kuorimuuttujien tavoin aliprosessit eivät peri paikallisia muuttujia. Myös paikallisia muuttujia ei voi viedä.

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *