Wyeksportować zmienną env, aby była dostępna we wszystkich podpowłokach i można ją zmodyfikować?

22

Załóżmy, że mam

export MY_VAR=0

w ~/.bashrc.

Mam otwarty terminal gnome iw tym terminalu zmieniam $MY_VARwartość na 200. Więc jeśli to zrobię

echo $MY_VAR

w tym terminalu 200pokazano.

Teraz otworzyłem kolejną kartę w terminalu gnomów i gotowe

echo $MY_VAR

... a zamiast tego 200mam 0.

Co powinienem zrobić, aby zachować wartość 200, gdy terminal modyfikuje zmienną środowiskową, dzięki czemu ta modyfikacja (ustawienie na 200) jest dostępna dla wszystkich kolejnych podpowłok i tym podobnych? czy to możliwe?

Ktoś nadal używa ciebie MS-DOS
źródło

Odpowiedzi:

23

Kopia z propaguje Środowiska do sub-skorup, więc to działa:

$ export MY_VAR=200
$ bash
$ echo $MY_VAR
200

ale ponieważ jest to kopia, nie można uzyskać tej wartości aż do powłoki nadrzędnej - przynajmniej przez zmianę środowiska.

Wygląda na to, że naprawdę chcesz pójść o krok dalej, czyli stworzyć coś, co będzie działać jak zmienna globalna, udostępniana przez powłoki „siostrzane” inicjowane oddzielnie od rodzica - jak twoja nowa karta w Gnome Terminal.

Najczęściej odpowiedź brzmi „nie możesz, ponieważ zmienne środowiskowe nie działają w ten sposób”. Istnieje jednak inna odpowiedź, a mianowicie, że zawsze możesz coś zhakować. Jednym podejściem byłoby zapisanie wartości zmiennej do pliku, na przykład ~/.myvar, a następnie włączenie jej do ~/.bashrc. Następnie każda nowa powłoka rozpocznie się od wartości odczytanej z tego pliku.

Możesz pójść o krok dalej - ustaw ~/.myvarformat MYVAR=200, a następnie ustaw PROMPT_COMMAND=source ~/.myvar, co spowoduje ponowne odczytanie wartości za każdym razem, gdy pojawi się nowy monit. To nie jest jeszcze dość zmienna globalna wspólna, ale to zaczyna zachowywać się jak to. Nie aktywuje się, dopóki nie pojawi się monit, co w zależności od tego, co próbujesz zrobić, może być poważnym ograniczeniem.

A potem, oczywiście, następną rzeczą jest automatyczne zapisanie zmian ~/.myvar. To staje się trochę bardziej skomplikowane i zamierzam zatrzymać się w tym miejscu, ponieważ tak naprawdę zmienne środowiskowe nie miały być mechanizmem komunikacji między powłokami i lepiej jest po prostu znaleźć inny sposób, aby to zrobić.

mattdm
źródło
10
Słyszę
Tak, przepraszam. Właśnie dlatego przestałem. :)
mattdm
„który polega na stworzeniu czegoś, co działa jak zmienna globalna” - Cóż, w rzeczy samej, to właśnie starałem się osiągnąć. ~ / .Myvar nie jest ładny, ale działa. Czy masz inną sugestię?
Ktoś nadal cię używa MS-DOS,
2
Cofnijmy się trochę. Dlaczego chcesz zmienną globalną?
mattdm
1
@mattdm: Mam pewne „biurokracje”, których muszę przestrzegać. Jednym z nich jest zestaw kodów, które muszę zatwierdzić wraz z komentarzem. Kody te znajdują się teraz w hierarchii folderów (strona główna / użytkownik / projekty / kod projektu / kod1 / kod2). Stworzyłem funkcję, która wyodrębnia kod1 i kod2 do zmiennych env (więc kiedy muszę wykonać działanie, po prostu wywołuję funkcję w katalogu z kodami), a one, podczas zatwierdzania, używam vima i są pewne funkcje, które przeczytaj te zmienne i wstaw komentarz automatycznie. Myślę, że użycie do tego plików może być rozwiązaniem.
Ktoś nadal cię używa MS-DOS
13

Załóżmy, że mam export MY_VAR=0w ~/.bashrc.

To właśnie twój błąd. Powinieneś zdefiniować swoje zmienne środowiskowe ~/.profile, które są odczytywane podczas logowania. ~/.bashrcSą odczytywane przy każdym uruchomieniu powłoki; kiedy uruchamiasz wewnętrzną powłokę, ona zastępuje MY_VAR. Jeśli tego nie zrobiłeś, Twoja zmienna środowiskowa propagowałaby w dół.

Aby uzyskać więcej informacji na temat ~/.bashrcvs ~/.profile, zobacz moje poprzednie posty na ten temat .

Zauważ, że propagacja w górę (uzyskanie zmodyfikowanej wartości z podpowłoki automatycznie odzwierciedlonej w powłoce nadrzędnej) nie jest możliwa, kropka.

Gilles „SO- przestań być zły”
źródło
3

W ogóle nie używaj zmiennych środowiskowych. Użyj plików.

Aby zapobiec wzajemnemu narzucaniu się procesów podczas aktualizacji / odczytu pliku, użyj plików blokujących i małych skryptów aktualizujących front-end, których celem jest tylko aktualizacja pliku za 1 $, jeśli nie jest zablokowany. Pliki blokujące są implementowane poprzez sprawdzenie, czy konkretny plik istnieje (/var/run/yourscript.lck), a jeśli tak, poczekaj, aż plik zniknie na chwilę, a jeśli nie, nie powiedzie się. Musisz także usunąć plik blokujący po zakończeniu aktualizacji pliku.

Przygotuj się na sytuację, w której skrypt nie może zaktualizować pliku, ponieważ plik jest zajęty.

LawrenceC
źródło
8
Sztuczka: używaj katalogów zamiast plików do blokowania, ponieważ mkdirdziała jako atomowy test-and-create.
mattdm
1
Jeśli chcecie porozmawiać o blokowaniu, równie dobrze możecie użyćflock(2)
Ehtesh Choudhury,
@mattdm Odkryłem, że dowiązanie symboliczne ln -s dummy lockfile(nawet jeśli jest zepsute) może również działać, ponieważ zawiedzie, jeśli dowiązanie symboliczne już istnieje. Zastanawiam się, jak to sprawdzić, czy to jest naprawdę w 100% bezpieczne.
Aquarius Power,
1

Kiedy właśnie przejrzałem to pytanie, próbowałem rozwiązać problem aktualizacji stanu (tj. Zmiennych powłoki) z podpowłoki. Aby można było przypisać zmienne, powiedzmy, wewnątrz potoku - a przypisanie byłoby transparentnie widoczne dla rodzica.

Oczywiście nie jest to możliwe w prosty sposób, ponieważ poszczególne części potoku są wykonywane w podpowłokach, które są forkedytowane z powłoki nadrzędnej, a zatem mają pamięć, która jest widokiem kopiowania przy zapisie w pamięci rodzica. Jednak przypuszczałem, że cienkie i przejrzyste rozwiązanie byłoby możliwe w oparciu o IPC typu „ pamięć współdzielona ” .

Znalazłem nawet implementację dokładnie tego projektu ... ale jest on w Perlu.

Dodanie tej odpowiedzi i tak jako możliwego rozwiązania.

ulidtko
źródło