Dozwolone znaki w nazwach zmiennych środowiskowych Linux

143

Jakie znaki są dozwolone w nazwach zmiennych środowiskowych systemu Linux? Moje pobieżne przeszukiwanie stron podręcznika systemowego i sieci dostarczyło jedynie informacji o tym, jak pracować ze zmiennymi, ale nie o tym, które nazwy są dozwolone.

Mam program Java, który wymaga zdefiniowanej zmiennej środowiskowej zawierającej kropkę, na przykład com.example.fancyproperty. W systemie Windows mogę ustawić tę zmienną, ale nie udało mi się ustawić jej w Linuksie (próbowałem w SuSE i Ubuntu). Czy ta nazwa zmiennej jest w ogóle dozwolona?

Christian Semrau
źródło
3
Na szczęście okazało się, że program jest równie zadowolony z właściwości systemowej Java (zadeklarowanej za pomocą -Dopcji wiersza poleceń), więc teraz działa. Oczywiście program wygląda w obu zestawach zmiennych, nie mówiąc mi o tym. Ale nadal jestem ciekawy, które nazwy zmiennych środowiskowych są dozwolone.
Christian Semrau
@AleksandrDubinsky Usunąłem to. To jest podobne, ale o definicji aliasu nie do końca zmienne środowiskowe stackoverflow.com/questions/24690640/ ...
Lime
1
Jeśli używasz Spring , domyślny SystemEnvironmentPropertySource również wyszuka com_example_fancypropertyi COM_EXAMPLE_FANCYPROPERTY.
Aleksandr Dubinsky,

Odpowiedzi:

203

Z The Open Group :

Te ciągi mają postać nazwa = wartość; nazwy nie mogą zawierać znaku „=”. Aby wartości mogły być przenoszone między systemami zgodnymi ze standardem IEEE 1003.1-2001, wartość powinna składać się ze znaków z przenośnego zestawu znaków ( z wyjątkiem NUL i jak wskazano poniżej ).

Nazwy mogą więc zawierać dowolny znak z wyjątkiem = i NUL, ale:

Nazwy zmiennych środowiskowych używane przez programy narzędziowe w tomie Shell and Utilities normy IEEE Std 1003.1-2001 składają się wyłącznie z wielkich liter, cyfr i znaku „_” (podkreślenia) ze znaków zdefiniowanych w Portable Character Set i nie zaczynają się od cyfry . Implementacja może zezwolić na inne znaki; wnioski będą tolerować obecność takich nazw.

Więc chociaż nazwy mogą być prawidłowe, twoja powłoka może nie obsługiwać niczego poza literami, cyframi i podkreśleniami.

Robert Gamble
źródło
8
Po prostu sprawdzam: drugi cytat jest nienormatywny: po prostu zauważa, że ​​zmienne, które POSIX definiuje jako specjalne dla swoich narzędzi, są [a-zA-Z_][a-zA-Z0-9_]*(domyślnie sugerując, że ta forma jest rozsądniejsza), ale rzeczywista specyfikacja (cytat 1) wymaga, aby cała implementacja obsługiwała wszystko oprócz =i NUL?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
3
Ponadto „przenośny zestaw znaków” pubs.opengroup.org/onlinepubs/000095399/basedefs/… zawiera spacje i materiały niedrukowalne: więc czy możemy ich używać, czy nie?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
3
To jest dokładnie to, co obserwuję. Shell nie lubi znaków specjalnych jako części nazwy zmiennej. Jednak gdy jeden program lub skrypt (np. Java lub perl) inicjuje zmienną ze znakami specjalnymi w nazwie i wywołuje inny plik wykonywalny (proces potomny), ten drugi plik wykonywalny może bez problemów uzyskać dostęp do tej zmiennej.
2015
1
@checksum, WIELKIE LITERY są jawnie określone dla nazw zmiennych, które mają znaczenie dla narzędzi określonych w POSIX, w tym dla powłoki; nazwy zawierające co najmniej jedną małą literę są jawnie zarezerwowane do użytku aplikacji. Dlatego najlepszą praktyką jest w rzeczywistości umieszczanie co najmniej jednej małej litery w nazwach zmiennych aplikacji, aby upewnić się, że nie zostanie ona przypadkowo nadpisana (ponieważ ustawienie zmiennej powłoki spowoduje nadpisanie dowolnej zmiennej środowiskowej o podobnej nazwie) zmiennej o znaczeniu system. Zobacz pubs.opengroup.org/onlinepubs/9699919799/basedefs/…
Charles Duffy
2
@CiroSantilli 烏坎 事件 2016 六四 事件 法轮功, możesz ich używać w zmiennych środowiskowych; nie można ich używać w zmiennych powłoki i nie ma gwarancji, że te zmienne środowiskowe będą dostępne z powłoki.
Charles Duffy
37

Sekcja standardów POSIX dotyczących powłok w IEEE Std 1003.1-2008 / IEEE POSIX P1003.2 / ISO 9945.2 Standard powłoki i narzędzi nie definiuje konwencji leksykalnej dla nazw zmiennych, jednak pobieżne spojrzenie na źródło ujawnia, że ​​używa czegoś podobnego do

[a-zA-Z_]+[a-zA-Z0-9_]*

(Edycja: Dodano brakujące podkreślenie w 2. klasie znaków.)

Krótka uwaga, ponieważ niektóre powłoki nie obsługują + w wyrażeniu regularnym, potencjalnie bardziej przenośnym wyrażeniem regularnym może być:

[a-zA-Z_]{1,}[a-zA-Z0-9_]{0,}

Aiden Bell
źródło
4
Dzięki, Aiden. Myślę, że w drugim zestawie nawiasów kwadratowych brakuje podkreślenia: Powinien prawdopodobnie brzmieć: [a-zA-Z_][a-zA-Z0-9_]* Dla takich jak ja, dla których odniesienie do bash-4.1 jest trochę niejasne (616 000 linii kodu), oto kilka wskazówek znajdź odpowiednie wiersze kodu: subst.c: param_expand(), in the default case-> general.h:/ * Określ dokładnie, z czego składa się legalny identyfikator powłoki. * / #define legal_variable_starter (c) (ISALPHA (c) || ​​(c == ' ')) #define legal_variable_char (c) (ISALNUM (c) || ​​c == ' ')
Chris
3
Nie potrzebujesz tego plusa w pierwszej klasie postaci.
scravy
2
@scravy true, chociaż wziąłem wyrażenie regularne ze źródła, więc zatrzymam + w.
Aiden Bell
4
POSIX definiuje: 3.231 Nazwa a word consisting solely of underscores, digits, and alphabetics from the portable character set. The first character of a name is not a digit .
Nie w sekcji powłoki, ale absolutnie istnieją standardy POSIX, które zawierają konwencje nazewnictwa zmiennych środowiskowych (a właściwie omawiają nazwy zarezerwowane do użytku przez powłokę). Zobacz pubs.opengroup.org/onlinepubs/9699919799/basedefs/…
Charles Duffy,
12

Moje szybkie testy pokazały, że zasadniczo przestrzegają tych samych reguł, co nazwy zmiennych w C, a mianowicie

  1. az, AZ _i 0-9
  2. NIE MOŻE zaczynać się od liczby

Więc to wyklucza .ich wewnątrz. Każda niedozwolona nazwa zmiennej jest przypisywana unknown command.

Zostało to przetestowane w ZSH, który jest w większości kompatybilny z BASH.

LukeN
źródło
6

Zależy od tego, co rozumiesz przez „dozwolone”.

Ignorowanie Windows na zawsze:

Środowisko to tablica ciągów przekazywana do głównej funkcji programu. Jeśli przeczytasz execve (2), nie zobaczysz żadnych wymagań ani ograniczeń dotyczących tych ciągów innych niż zakończenie zerowe.

Zgodnie z konwencją, każdy ciąg składa się z NAZWA = wartość. Nie ma konwencji cytowania, więc nie możesz mieć znaku „=” w nazwie w tej konwencji.

Normalni ludzie ustalają te warunki, omawiając je ze swoją skorupą. Każda powłoka ma swoje własne pomysły na temat prawidłowych zmiennych NAME, więc musisz przeczytać stronę podręcznika dla powłoki chwili, aby zobaczyć, co o tym myśli.

Ogólnie rzecz biorąc, rzeczy takie jak com.baseball.spit = fleagh są właściwościami systemowymi Javy i niezależnie od tego, czy jakiś program Java chce wrócić do środowiska, lepiej jest określić je za pomocą -D.

bmargulies
źródło
Powinienem był wcześniej dojść do wniosku, że zmienna jest sformatowana jak właściwość systemowa Java, zamiast próbować ustawić ją jako zmienną środowiskową.
Christian Semrau
5

To zależy od powłoki. Domyślam się, że używasz basha domyślnie, w którym to przypadku litery, cyfry i podkreślenia są dozwolone, ale nie możesz rozpocząć nazwy zmiennej liczbą. Od wersji Bash v.3 kropki nie są dozwolone w nazwach zmiennych .

ire_and_curses
źródło
4

TAK, MOŻESZ TO ZROBIĆ.

Użyj execienv polecenie, aby zaimplementować tę scenę.

Testuj urządzenie w Dockerze

docker run -it --rm alpine:3.10

Uruchom polecenie w kontenerze:

exec env spring.application_name=happy-variable-name ${SHELL:-/bin/sh}

Sprawdź zmienne środowiskowe:

HOSTNAME=bd0bccfdc53b
SHLVL=2
HOME=/root
spring.application_name=happy-variable-name
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/

Służy ps auxdo sprawdzania, czy PID nie został zmieniony

PID   USER     TIME  COMMAND
    1 root      0:00 /bin/sh
   12 root      0:00 ps aux

Służy pythondo weryfikacji zmiennej środowiskowej

apk add python
python -c 'import os; print(os.environ["spring.application_name"])'

OUTPUT jest happy-variable-name .

Co się stało?

  1. Wywołanie wbudowanej powłoki exec
  2. Wbudowane wywołanie exec w powłoce syscall.exec tworzy proces „env” w celu zastąpienia bieżącej powłoki
  3. proces env wywołaj syscall.execvp utwórz proces '/ bin / sh', aby zastąpić proces env

Inny sposób

  • Obraz platformy Docker

Jeśli używasz Dockera, możesz ustawić zmienną w Dockerfile

FROM busybox
ENV xx.f%^&*()$#ff=1234
  • Mapa konfiguracji Kubernetes

Jeśli używasz kubernetes, możesz ustawić zmienną za pomocą ConfigMap

test.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: foo-config
data:
  "xx.ff-bar": "1234"

---
apiVersion: v1
kind: Pod
metadata:
  name: foobar
spec:
  containers:
    - name: test-container
      image: k8s.gcr.io/busybox
      command: [ "/bin/sh", "-c", "env" ]
      envFrom:
      - configMapRef:
          name: foo-config
  restartPolicy: Never

Wdróż pod kubectl apply -f test.yaml

Sprawdź kubectl logs foobarwyjście:

xx.ff-bar=1234

ConfigMap zezwala na „-”, „_” lub „.”

Gorliwość
źródło
0

Podczas gdy większość powłok nie pozwala na ustawienie zmiennych środowiskowych (jak wspomniano w innych odpowiedziach), jeśli potrzebujesz, możesz uruchomić inne programy z niestandardowymi zmiennymi środowiskowymi używając env(1) .

Na przykład, wymazanie całego środowiska i ustawienie Strange.Env:Varna wartość foooraz wykonanie programu w Perlu, który je drukuje:

env -i Strange.Env:Var=foo perl -MData::Dumper -E 'say Dumper(\%ENV)'

wydrukuje

$VAR1 = {
          'Strange.Env:Var' => 'foo'
        };
Matija Nalis
źródło