Czym dokładnie jest zmienna środowiskowa?

42

Wiem, że VARIABLE=valuetworzy zmienną środowiskową i export VARIABLE=valueudostępnia ją procesom tworzonym przez bieżącą powłokę. envpokazuje bieżące zmienne środowiskowe, ale gdzie one mieszkają? Co obejmuje zmienną środowiskową (lub środowisko , jeśli o to chodzi)?

Matt
źródło

Odpowiedzi:

29

Środowisko nie jest tak magiczne, jak mogłoby się wydawać. Powłoka przechowuje ją w pamięci i przechodzi do execve()wywołania systemowego. Proces potomny dziedziczy go jako wskaźnik tablicy o nazwie environ. Z strony execvepodręcznika:

STRESZCZENIE

   #include <unistd.h>

   int execve(const char *filename, char *const argv[],
              char *const envp[]);

argvto tablica ciągów argumentów przekazanych do nowego programu.
Zgodnie z konwencją pierwszy z tych ciągów powinien zawierać nazwę pliku powiązaną z wykonywanym plikiem. envpjest tablicą ciągów, zwykle o postaci klucz = wartość, które są przekazywane jako środowisko do nowego programu.

Strona environ(7)oferuje również wgląd:

STRESZCZENIE

   extern char **environ;

OPIS

Zmienna environwskazuje na tablicę wskaźników na ciągi zwane „środowiskiem”. Ostatni wskaźnik w tej tablicy ma wartość NULL. (Ta zmienna musi zostać zadeklarowana w programie użytkownika, ale jest zadeklarowana w pliku nagłówkowym, <unistd.h>jeśli pliki nagłówkowe pochodzą z libc4 lub libc5, a jeśli pochodzą z glibc i zdefiniowano _GNU_SOURCE.) Ta tablica ciągów jest dostępna dla proces wywołany przez exec (3), który rozpoczął proces.

Obie strony GNU są zgodne ze specyfikacją POSIX

Jordan
źródło
4
+1 prawdopodobnie warto zauważyć, że niektórzy członkowie exec(3)rodziny (tj. Ci, którzy nie pasują do exec * v) przechodzą ** environment pod przykryciem.
msw
5
Zauważ, że nie chodzi tu o procesy potomne (procesy potomne dziedziczą całą pamięć ich rodzica), ale o wykonywane programy (w tym samym procesie), więc jest to inny sposób przekazywania danych przez wywołanie systemowe execve (), które w przeciwnym razie wyczyści pamięć procesu).
Stéphane Chazelas,
@msw: To exec*ewarianty, które jawnie przekazują env, zamiast domyślnie używać environzmiennej globalnej. v„Wektor” oznacza i odnosi się do argumentów polecenia przekazywane jako matrycy (raczej niż „liście” (funkcja zmiennej długości)) execvejest połączeniem systemu i wszystkie inne exec*funkcje libc opakowania na nim.
Peter Cordes,
19

Po prostu źle to zrobisz: SOME_NAME=valuetworzy zmienną powłoki (w większości powłok). export SOME_NAME=valuetworzy zmienną środowiskową. Na lepsze na gorsze, większość powłok Unix / Linux / * BSD używa identycznej składni w dostępie do zmiennych środowiskowych i zmiennych powłoki.

W pewnym szerszym znaczeniu „środowisko” to tylko informacja, która towarzyszy wykonywaniu programu. W programach C, można znaleźć identyfikator procesu z getpid()połączenia w programie Shell należałoby użyć zmiennej dostępu: $$. Identyfikator procesu jest tylko częścią środowiska programu. Uważam, że termin „środowisko” pochodzi z niektórych bardziej teoretycznych zagadnień informatycznych, takich jak modelowanie wykonania programu. Modele wykonania programu mają środowisko „, które zawiera powiązania między zmiennymi a ich wartościami”.

I ta ostatnia, silniejsza definicja jest tym, czym jest „środowisko” dla powłok Unix / Linux / * BSD: związek między nazwami („zmiennymi”) i ich wartościami. W przypadku większości powłok w stylu uniksowym wszystkie wartości są ciągami znaków, chociaż nie jest to tak ściśle prawdziwe, jak kiedyś. Ksh, Zsh i Bash mają teraz zmienne maszynowe. Nawet definicje funkcji powłoki mogą być eksportowane.

Użycie środowiska odrębnego od zmiennych zwykłej powłoki obejmuje fork/execmetodę uruchomienia nowego procesu używanego przez wszystkie Uniksy. Kiedy jesteś exportparą nazwa / wartość, ta para nazwa / wartość będzie obecna w środowisku nowych plików wykonywalnych, uruchamianych przez powłokę za pomocą execve(2)wywołania systemowego (zwykle po znaku fork(2), z wyjątkiem sytuacji, gdy execużyto polecenia powłoki).

Po an execve(), main()funkcja nowego pliku binarnego ma swoje argumenty wiersza poleceń, środowisko (przechowywane jako tablica wskaźników zakończonych znakiem NULL do var=valuełańcuchów, patrz environ(7)strona man). Inny odziedziczony stan obejmuje ulimitustawienia, bieżący katalog roboczy i wszelkie otwarte deskryptory plików, dla których program execve()wywołujący nie miał ustawionego FD_CLOEXEC. Bieżący stan tty (włączony echo, tryb raw itp.) Można również uznać za część stanu wykonania odziedziczonego przez nowo opracowany execproces.

Zobacz bashopis środowiska wykonawczego w podręczniku dla prostych poleceń (innych niż funkcje wbudowane lub powłoki).

Środowisko uniksowe różni się od co najmniej niektórych innych systemów operacyjnych: „leksyki” VMS można zmienić w procesie potomnym, a zmiana ta była widoczna w obiekcie nadrzędnym. VMS cdw procesie potomnym wpłynie na katalog roboczy rodzica. Przynajmniej w niektórych okolicznościach, a moja pamięć może mnie zawodzić.

Niektóre zmienne środowiskowe są dobrze znane $HOME, $PATH, $LD_LIBRARY_PATHi innych. Niektóre są konwencjonalne dla danego systemu programowania, dzięki czemu powłoka nadrzędna może przekazywać do programu wiele informacji specjalnych, takich jak określony katalog tymczasowy lub identyfikator użytkownika i hasło, które się nie wyświetlają ps -ef. Proste programy CGI dziedziczą wiele informacji z serwera WWW na przykład poprzez zmienne środowiskowe.

Bruce Ediger
źródło
1
Wydawałoby się to trochę bardziej skomplikowane. W bash przynajmniej SOME_NAME=value commandustawi zmienną środowiskową SOME_NAME dla tego wywołania polecenia. Mylące wydaje się, że nie ustawia zmiennej powłoki o tej samej nazwie.
Samuel Edwin Ward
2
Mówiąc ściślej, zmienne środowiskowe nie są dziedziczone, ale raczej jawnie przekazywane z powłoki do programów, które ona tworzy.
msw
2
@SamuelEdwinWard, dlaczego SOME_NAME=value commandzachowujesz się wbrew oczekiwaniom, jest to, że jest to specjalna składnia oznaczająca „dodaj SOME_NAME do środowiska przekazanego do komendy, ale w żaden inny sposób nie zmieniaj zmiennych tej powłoki”.
msw
1
Fascynujące, link do rachunku lambda / programowania funkcjonalnego. To ciekawe połączenie, które ma sens.
Matt
1
Niektóre z nich nie są całkiem właściwe. Na przykład, podpowłok są potomne i powinny być fork()ed, ale do otrzymania (kopie) zmiennych powłoki.
ruakh
7

Zmienne środowiskowe w swojej najbardziej surowej formie to tylko zestaw par nazwa / wartość. Jak opisano w bash man page ( man 1 bash) w sekcji ENVIRONMENT:

   When  a  program  is invoked it is given an array of strings called the
   environment.   This  is  a  list  of  name-value  pairs,  of  the  form
   name=value.

   The  shell  provides  several  ways  to manipulate the environment.  On
   invocation, the shell scans its own environment and creates a parameter
   for  each name found, automatically marking it for export to child pro-
   cesses.  Executed commands inherit the  environment.

W praktyce pozwala zdefiniować zachowanie wspólne lub unikalne dla programów wywoływanych z obecnej powłoki. Na przykład podczas używania crontablub visudomożna zdefiniować EDITORzmienną środowiskową, aby zdefiniować inny edytor inny niż domyślnie używany przez system. To samo można powiedzieć o manpoleceniu, które patrzy na twoje PAGERśrodowisko, aby dowiedzieć się, z jakiego programu stronicującego należy korzystać do wyświetlania wyników strony podręcznika.

Sporo poleceń unixowych odczytuje środowisko i zależnie od tego, co jest tam ustawione, zmienia ich wyjście / przetwarzanie / działanie w zależności od nich. Niektóre są udostępniane, niektóre są unikalne dla programu. Większość stron podręcznika zawiera informacje o tym, jak zmienna środowiskowa wpływa na opisywany program.

Inne praktyczne ilustracje dotyczą np. Systemów z kilkoma instalacjami Oracle na tej samej platformie. Przez ustawienie ORACLE_HOMEcały zestaw poleceń Oracle (wczytanych ze PATHzmiennej środowiskowej) następnie pobiera ustawienia, definicje, mapowania i biblioteki z tego katalogu najwyższego poziomu. To samo dotyczy innych programów, takich jak Java z jego JAVA_HOMEzmienną środowiskową.

bash sam ma wiele zmiennych środowiskowych, które mogą zmienić zachowanie różnych rzeczy z historii ( HISTSIZE, HISTFILEitp), wielkość ekranu ( COLUMNS), zakończenie zakładki ( FIGNORE, GLOBIGNORE) Ustawienia regionalne i kodowania znaków / dekodowania ( LANG, LC_*), szybka ( PS1.. PS4), oraz itd. (ponownie szukaj wiedzy na stronie podręcznika użytkownika bash).

Możesz także pisać skrypty / programy korzystające z własnych niestandardowych zmiennych środowiskowych (do przekazywania ustawień lub zmiany funkcjonalności).

Drav Sloan
źródło
0

„Zmienne środowiskowe” to zestaw dynamicznych nazwanych wartości, które mogą wpływać na zachowanie zachodzących procesów na komputerze.

Są częścią środowiska operacyjnego, w którym działa proces. Na przykład działający proces może zapytać o wartość zmiennej środowiskowej TEMP, aby znaleźć odpowiednią lokalizację do przechowywania plików tymczasowych, lub zmienną HOME lub USERPROFILE, aby znaleźć strukturę katalogów należącą do użytkownika uruchamiającego proces.

Więcej informacji tutaj → http://en.wikipedia.org/wiki/Environment_variable .

Wszystko, co chcesz wiedzieć o zmiennych środowiskowych ... ↑

SoCalDiegoRob
źródło
1
Chociaż jest mało prawdopodobne, że linki te znikną, lepiej odpowiedzieć na pytanie tutaj odpowiednim tekstem i podać link jako dodatek do informacji zapasowych.
Anthon
@Anthon Uważam, że masz rację i dokonam zmian tak szybko, jak to możliwe ... Dzięki za radę ...
SoCalDiegoRob
-1

Ta odpowiedź wymaga nieco doświadczenia w skryptowaniu powłoki i znajomości terminów zmienna, wartość, podstawianie zmiennych, monit, echo, jądro, powłoka, narzędzie, sesja i proces.

Zmienna (envar) to zestaw globalnych zdefiniowanych zmiennych, które może mieć wpływ na sposób, w jaki dana procesy będą zachowywać się w systemie operacyjnym komputera.

1. Przykładowe wprowadzenie:

Zastępujemy envary literami$ ai wielkimi literami . Na przykład: $PS1.

Możemy wydrukować envar w ten sposób:

echo $PS1

$PS1przechowuje wartość monitu Unix. Powiedz, że jego natywnymi wartościami są \u \w $.

  • \u oznacza (obecnego) użytkownika,
  • \w oznacza katalog roboczy,
  • $ jest obramowanie monitu.

Tak więc, jeśli robimy: echo $PS1widzimy wartości \u, \wplus znak dolara w końcu.

Moglibyśmy zmienić zachowanie Unixa w tym kontekście, jeśli zmienimy wartości tej envory. Na przykład:

PS1="\w >"

Teraz monit wygląda następująco (zakładając, że katalog roboczy nosi nazwę „John”):

John >

W ten sam sposób, w jaki moglibyśmy to zrobić PS1="Hello, I'm your prompt >", echo $PS1przyniosą:

Hello, I'm your prompt >

W Bash 4.xx możemy wydrukować WSZYSTKIE envary w systemie za pomocą envpolecenia. Sugeruję wykonanie envw terminalu i przyjrzenie się wynikowi.

2. W jaki sposób te dane są pokazywane i przetwarzane:

Terminal sesji pozwala nam dostosować envary, które nadchodzą z Bash.

Powyższe zmiany są zwykle tymczasowe i oto dlaczego:

Każda sesja (która nie jest podsesją) jest unikalna, a kilka procesów może być uruchomionych jednoznacznie w tym samym czasie (każda z własnym zestawem envarów), ale zwykle istnieje dziedziczenie od sesji 0 do sesji 1 i wyższych.

Zmiany, które wprowadzamy w jednym procesie, są dla niego unikalne i przestaną obowiązywać, jeśli zamkniemy go bez zapisania go w jakiś sposób.

Jak więc zapisać te zmiany:

Istnieje kilka rodzajów sposobów przechowywania zmian envar, w zależności od wybranego zakresu. Oto różne zakresy (poziomy) takich zmian:

  • Poziom procesu: Envary są dostępne tylko dla programów w bieżącej sesji.
  • Poziom eksportu: envary są dostępne dla programów w bieżącej sesji lub wszystkich jej podsesjach .
  • Poziom globalny: zmiany będą przechowywane dla wszystkich sesji (podstawowej i wszystkich subskrybentów).

Gdzie są przechowywane dane envar:

Unix składa się z 3 głównych warstw: jądra, powłoki i narzędzi. AFAIK każda powłoka ma własne envary, które są zbudowane głównie lub wyłącznie w powłoce.

Specyficzna lokalizacja, w której się globalnie zmienić te zazwyczaj /etc/profilechoć możemy również zrobić w .bashrcoczywiście.

3. Tworzenie nowych envars:

Możemy tworzyć nowe envary i oto jest sposób; od wersji Bash 4.xx nie ma natywnej enavar o nazwie MESSAGE(jak powiedziano, envary są zwykle pisane wielkimi literami).

MESSAGE="Hello world!"

stworzy go dla nas, a teraz, jeśli napiszemy echo $MESSAGE, otrzymamy hello world!.

Jeśli wykonamy bashw bieżącej sesji roboczej (okno), zaczniemy nową podsekcję bash i nie będziemy już działać w pierwotnym procesie, chyba że wykonamy exit.

Uwaga: W systemach operacyjnych z emulatorem terminali (takich jak Ubuntu Desktop) podsekcja zwykle działa w tym samym oknie, ale nowa sesja w innym oknie nie jest podsesją istniejącej (jest to proces sąsiedni ) .

Uwaga: Nie używaj specjalnych znaków w wartościach envar, takich jak! albo nie zostaną uratowani.

Eksportowanie envara z oryginalnej sesji do wszystkich podsesji:

Nadal możemy używać envara utworzonego w pierwszej sesji, również w drugiej, bez rejestrowania go w plikach conf na poziomie użytkownika lub globalnym (patrz następujące dane). Oto jak to zrobić:

Przejdź do oryginalnej sesji (w bieżącym oknie lub w innym) i wykonaj:

export MESSAGE

podczas eksportowania nie używaj $znaku.

Jest teraz eksportowany do wszystkich podsesji. Jeśli wykonasz echo $MESSAGEsesję podrzędną, niezależnie od tego, czy pochodzi ona od użytkownika, czy inna, zostanie ona wydrukowana.

Zauważ, że wewnętrzne zmienne Shell, takie jak PS1nie powinny być eksportowane, ale jeśli chcesz je wyeksportować z dowolnego powodu i nie pojawiają się, nie wykonuj bashpóźniej export, ale raczej bash –norc.

4. Envar $ PATH:

$PATH to środowisko, które użytkownicy najczęściej zmieniają najbardziej.

Jeśli my echo $PATH, zobaczymy ten strumień:

/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

Wydrukowane wartości tego envaru są oddzielone dwukropkami (:) tam, ale oto potencjalnie wygodniejszy sposób (są to te same wartości):

/usr/local/bin
/usr/bin
/bin
/usr/local/games
/usr/games

Są to katalogi, których należy szukać, gdy uruchamiamy narzędzie.

Wykonując which echo, uzyskamy lokalizację jego pliku - na przykład możemy zobaczyć, że istnieje /bin/echo.

Na tej podstawie nie musimy wpisywać echa envar, aby wyświetlić wartości evnar. Możemy również wykonać:

/bin/echo $ENVAR

Envar będzie nadal wykonywany, na przykład:

/bin/echo $HOME

Daje nam

/home/User || /root

Tak jak:

echo $HOME

Daje nam

/home/User || /root

Uwaga: w $HOMEskrócie ~.

Relacje system-$ PATH i możliwa interakcja użytkownika:

W Bash 4.xx, kiedy używamy narzędzia bez pełnej ścieżki, system użyje wszystkich 6 wartości wymienionych powyżej $PATHenvar. Tak więc zacznie się /user/local/bini będzie śledził całą zawartość w poszukiwaniu echopliku wykonywalnego.

W takim przypadku zatrzyma się na /bin/echo, w którym w tym przypadku znajduje się plik wykonywalny.

Dlatego głównym powodem, dla którego możemy dostosować $PATHenvar, jest instalowanie plików wykonywalnych, które nie mieszczą się w żadnej z jego wartości natywnych.

Po zainstalowaniu takich plików wykonywalnych powinniśmy odpowiednio ustawić ich $PATHwartość, a następnie moglibyśmy z nimi pracować.

5. Dodatek - rozszerzenie $PATH:

Możemy export $PATHrozbić pod sesje (w tym rozszerzenia bash, takie jak WP-CLI dla WordPress lub Drush dla Drupal) w ten sposób:

export PATH="/home/John:$PATH"

Spowoduje to dodanie nowej wartości /home/Johndo $PATH, a następnie w prawo potem, to załącza żadnych wartości rodzimych do niego (z prawej po dwukropku), które są przechowywane zgodnie ze składnią $PATH.

Taką stałą zmianę można wykonać w odpowiednim skrypcie, zwykle pod /etc/profilei pod nazwą .bashrc.

JohnDoea
źródło
3
Jest bardzo źle z tą odpowiedzią: połączenie sesji i procesów, ostrzeżenie o !niedziałającej wartości zmiennej środowiskowej, która znajduje się tuż pod przykładem pokazującym, że działa, fałszywe pojęcie podsesji, dość dziwna rada co robić po wyeksportowaniu zmiennej powłoki i fałszywym pojęciu globalnych zmiennych środowiskowych.
JdeBP
warning about ! in an environment variable value not working that is right below an example showing it working? Proszę przykład.
JohnDoea
quite bizarre advice about what to do after exporting a shell variable, co dokładnie masz na myśli?
JohnDoea,
false notion of global environment variables, co dokładnie masz na myśli?
JohnDoea