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
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 kutsuexport
). - 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ä.
FOO=bar
, se asettaa nykyisen kuoriprosessin arvon. Jos suoritan sitten ohjelman, kuten (bundle install
), se luo aliprosessin, joka ’ ei pääseFOO
. Mutta jos olisin sanonutexport FOO=bar
, lapsiprosessilla (ja sen jälkeläisillä) olisi pääsy siihen. Yksi heistä voisi puolestaan kutsuaexport FOO=buzz
muuttamaan jälkeläistensa arvoa tai vainFOO=buzz
muuttamaan arvoa vain itselleen . Onko se totta?