Czy zmienne takie jak 0 $ i 1 $ zmienne środowiskowe / zmienne?


17

Są to zmienne w powłoce jak $0, $1, $2, $?, itd.

Próbowałem wydrukować powłokę i zmienne środowiskowe za pomocą następującego polecenia:

set

Ale tych zmiennych nie było na liście.

Zasadniczo te zmienne nie są uważane za zmienne powłoki / środowiska, prawda? (nawet jeśli je wyprowadzasz, musisz poprzedzić je znakiem $, podobnie jak w przypadku zmiennych powłoki / środowiska)


3
Parametry pozycyjne nie są zmiennymi. Nie możesz export 3zmienić się $3w zmienną środowiskową. Nie możesz unset 3; i nie można przypisać $3nowej wartości za pomocą 3=val.
Kaz

Odpowiedzi:


25

Zmienne są jedną z trzech różnych odmian parametrów w powłoce.

  1. Zmienna jest parametrem, którego nazwa jest poprawnym identyfikatorem powłoki; zaczyna się od _litery lub litery, po której następuje zero lub więcej liter, cyfr lub _.
  2. W pozycyjne parametry są numerowane parametry $1, $2...
  3. Wszystkie parametry specjalne mają nazwy jednoznakowe, a poza $0tym wszystkie są różnymi znakami interpunkcyjnymi.

set wyświetla tylko zmienne powłoki.

Podzbiorem zmiennych powłoki są zmienne środowiskowe, których wartości są albo dziedziczone ze środowiska podczas uruchamiania powłoki, albo są tworzone przez ustawienie exportatrybutu na prawidłową nazwę.


1
Zauważ, że setwyświetla wszystkie parametry w zsh(nie $ 1, 2 $ ... ale $ *, $ @) oraz funkcje w bash i bosh. Niektóre powłoki, takie jak ksh93 i starsze wersje kreskowych zmiennych wyjściowych env, które nie zostały zmapowane na zmienne powłoki. ( env 1=foo ksh -c setdrukuje się 1=foo)
Stéphane Chazelas

11

Zmienne środowiskowe a parametry pozycyjne

Zanim zaczniemy omawiać $INTEGERtypy zmiennych, musimy zrozumieć, czym one naprawdę są i czym różnią się od zmiennych środowiskowych. Zmienne takie jak $INTEGERnazywane są parametrami pozycyjnymi. Jest to opisane w standardzie POSIX (Portable Operating System Interface), sekcja 2.1 (wyróżnienie moje):

  1. Powłoka wykonuje funkcję (patrz Polecenie dotyczące definicji funkcji), wbudowaną (patrz Specjalne narzędzia wbudowane), plik wykonywalny lub skrypt, podając nazwy argumentów jako parametry pozycyjne ponumerowane od 1 do n oraz nazwę polecenia (lub w przypadku funkcji w skrypcie, nazwa skryptu) jako parametr pozycyjny o numerze 0 (patrz Wyszukiwanie i wykonywanie poleceń).

Natomiast zmienne takie jak $HOMEi $PATHsą zmiennymi środowiskowymi. Ich definicja jest opisana w rozdziale 8 normy :

Zmienne środowiskowe zdefiniowane w tym rozdziale wpływają na działanie wielu narzędzi, funkcji i aplikacji. Istnieją inne zmienne środowiskowe, które są interesujące tylko dla określonych narzędzi. Zmienne środowiskowe, które dotyczą tylko jednego narzędzia, są zdefiniowane jako część opisu narzędzia.

Zwróć uwagę na ich opis. Parametry pozycyjne mają pojawiać się przed poleceniem, tj command positional_arg_1 positional_arg_2.... Są one przeznaczone do dostarczenia przez użytkownika, aby powiedział polecenie, co konkretnie zrobić. Kiedy to zrobisz echo 'Hello' 'World', wydrukuje ciągi Helloi World, ponieważ są to parametry pozycyjne dla echo- rzeczy, na których chcesz echooperować. I echojest zbudowany w taki sposób, że rozumie parametry pozycyjne jako ciągi znaków do wydrukowania (chyba że są jedną z opcjonalnych flag takich jak -n). Jeśli zrobisz to z innym poleceniem, może nie zrozumieć, co HelloiWorldto dlatego, że może oczekuje liczby. Zauważ, że parametry pozycyjne nie są „dziedziczone” - proces potomny nie wie o parametrach pozycyjnych elementu nadrzędnego, chyba że zostanie jawnie przekazany do procesu potomnego. Często widzisz parametry pozycyjne przekazywane za pomocą skryptów otoki - tych, które mogą sprawdzać, czy istnieje już instancja polecenia lub dodawać dodatkowe parametry pozycyjne do rzeczywistego polecenia, które zostanie wywołane.

Natomiast zmienne środowiskowe mają wpływać na wiele programów. Są to zmienne środowiskowe , ponieważ są ustawione poza samym programem (więcej na ten temat poniżej). Niektóre zmienne środowiskowe, takie jak HOMElub PATHmają określony format, konkretne znaczenie i będą oznaczały to samo dla każdego programu. HOMEzmienna będzie oznaczać to samo dla zewnętrznego narzędzia, takiego jak dla /usr/bin/findtwojej powłoki (aw konsekwencji dla skryptu) - jest to katalog domowy nazwy użytkownika, pod którym działa proces. Zauważ, że na przykład zmienne środowiskowe mogą służyć do uwzględnienia określonego zachowania poleceniaUIDzmiennej środowiskowej można użyć do sprawdzenia, czy skrypt działa z uprawnieniami administratora, czy też nie, i odpowiednio rozgałęzić do określonych akcji. Zmienne środowiskowe są dziedziczone - procesy potomne otrzymują kopię środowiska rodzica. Zobacz także Jeśli procesy dziedziczą środowisko rodzica, dlaczego potrzebujemy eksportu?

Krótko mówiąc, główne rozróżnienie polega na tym, że zmienne środowiskowe są ustawiane poza poleceniem i nie powinny być zmieniane (zwykle), podczas gdy parametry pozycyjne to rzeczy, które mają być przetwarzane przez polecenie i zmieniają się.


Nie tylko koncepcje powłoki

W komentarzach zauważyłem, że mieszasz terminal i powłokę i naprawdę polecam przeczytanie o prawdziwych terminalach, które kiedyś były urządzeniami fizycznymi. W dzisiejszych czasach „terminal”, do którego zwykle się odnosimy, to okno z czarnym tłem i zielonym tekstem jest w rzeczywistości oprogramowaniem, procesem. Terminal to program, który uruchamia powłokę, podczas gdy powłoka jest także programem, który odczytuje to, co wpisujesz, aby wykonać (to znaczy, jeśli jest to powłoka interaktywna; powłoki nieinteraktywne to skrypty i sh -c 'echo foo'typy wywołań). Więcej o muszlach tutaj .

Jest to ważne rozróżnienie, ale także ważne, aby uznać, że terminal jest programem i dlatego przestrzega tych samych reguł środowiska i parametrów pozycyjnych. Twoje gnome-terminalpo uruchomieniu spojrzy na twoją SHELLzmienną środowiskową i stworzy dla ciebie odpowiednią domyślną powłokę, chyba że podasz inne polecenie-e . Powiedzmy, że zmieniłem domyślną powłokę na ksh - gnome-terminal kshzamiast tego odrodzi się bash. To także przykład wykorzystania środowiska przez programy. Gdybym wyraźnie powiedzieć gnome-terminalze -euruchomić specyficzną otoczkę - będzie to zrobić, ale to nie będzie trwały. Natomiast środowisko ma być w większości niezmienione (więcej na ten temat później).

Jak widać, zmienne środowiskowe i pozycyjne są właściwościami procesu / polecenia, a nie tylko powłoki. Jeśli chodzi o skrypty powłoki, postępują one zgodnie z modelem ustawionym przez język programowania C. Weźmy na przykład funkcję C, mainktóra zazwyczaj wygląda

int main(int argc, char **argv)

, gdzie argcjest liczba argumentów wiersza polecenia i argvefektywnie tablica parametrów wiersza polecenia, a następnie jest environfunkcja (w Linuksie, która man -e 7 environ), aby uzyskać dostęp do takich rzeczy, jak ścieżka katalogu domowego użytkownika, lista katalogów, w PATHktórych możemy szukać plików wykonywalnych itp. Skrypty powłoki są również modelowane w podobny sposób. W terminologii powłoki mamy parametrów pozycyjnych $1, $2i tak dalej, podczas gdy $#wiele parametrów pozycyjnych. Co $0? To jest nazwa samego pliku wykonywalnego, który również jest modelowany z języka programowania C - argv[0]będzie to nazwa twojego „pliku wykonywalnego”. Dotyczy to w większości języków programowania i skryptów .

Powłoki interaktywne a nieinteraktywne

Jedną z rzeczy, o których już wspomniałem, jest rozróżnienie między powłokami interaktywnymi i nieinteraktywnymi . Monit, w którym wpisujesz polecenia - jest interaktywny, wchodzi w interakcję z użytkownikiem. Natomiast gdy masz skrypt powłoki lub uruchamiasz go bash -c''w sposób nieinteraktywny.

I tu właśnie ważne staje się rozróżnienie. Powłoka jest uruchomienie już jest procesem, który zrodził się z parametrów pozycyjnych (na bashpowłokę logowania jest jeden „... którego pierwszy znak argumentu jest zerowy. - lub jeden uruchomiono z opcją --login” ( odniesienie ) )

Natomiast skrypty i powłoki uruchamiane z -copcją mogą korzystać z argumentów $1i $2argumentów. Na przykład,

$ bash -c 'echo $1; stat $2' sh 'Hello World' /etc/passwd
Hello World
  File: '/etc/passwd'
  Size: 2913        Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d  Inode: 6035604     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2017-08-12 14:48:37.125879962 -0600
Modify: 2017-08-12 14:48:37.125879962 -0600
Change: 2017-08-12 14:48:37.137879811 -0600
 Birth: -

Zauważ, że też shtam użyłem , ponieważ małe dziwactwo -copcji polega na przyjęciu pierwszego parametru pozycyjnego i przypisaniu go $0, w przeciwieństwie do typowej nazwy programu.

Inną rzeczą, na którą należy zwrócić uwagę, jest to, że parametry pozycyjne nazywam „ramkami”. Zauważ, że najpierw uruchomiliśmy bashz własnymi parametrami pozycyjnymi, ale te parametry pozycyjne stały się parametrami do echoi stat. I każdy program rozumie to na swój sposób. Gdybyśmy podali statciąg Hello Worldi nie ma pliku Hello World, spowodowałby to błąd; bashtraktuje go jak zwykły ciąg, ale statoczekuje, że będzie to istniejąca nazwa pliku. Natomiast wszystkie programy zgodziłyby się, że zmienna środowiskowa HOMEjest katalogiem (chyba że programista zakodował ją w nieuzasadniony sposób).


Czy możemy sobie poradzić ze zmiennymi środowiskowymi i parametrami pozycyjnymi?

Technicznie rzecz biorąc, możemy sobie poradzić z obydwoma, ale nie powinniśmy bawić się zmiennymi środowiskowymi, podczas gdy często musimy podawać parametry pozycyjne. Możemy uruchamiać polecenia w powłoce z przygotowaniem zmiennej, na przykład:

$ hello=world bash -c 'echo $hello'
world

Możemy również umieszczać zmienne w środowisku, korzystając export variable=valuez powłoki lub skryptu. Lub możemy uruchomić polecenie z całkowicie pustym środowiskiem za pomocą env -c command arg1 arg2. Zazwyczaj jednak nie zaleca się manipulowania środowiskiem, szczególnie przy użyciu dużych liter lub zastępowania już istniejących zmiennych środowiskowych. Zauważ, że jest to zalecane, choć nie jest standardem.

W przypadku parametrów pozycyjnych sposób ich ustawiania jest oczywisty, po prostu dodaj je do polecenia, ale są też sposoby, aby ustawić je w inny sposób , a także zmienić listę tych parametrów za pomocą shiftpolecenia.

Podsumowując, cel tych dwóch celów jest inny i istnieją one z jakiegoś powodu. Mam nadzieję, że ludzie uzyskali wgląd w tę odpowiedź i fajnie było ją przeczytać, tak jak dla mnie napisanie tej odpowiedzi.


Uwaga dotycząca polecenia set

setRozkaz, zgodnie z instrukcją zachowuje się jak w przykładzie (od instrukcji bash nacisk dodano):

Bez opcji nazwa i wartość każdej zmiennej powłoki są wyświetlane w formacie, który można ponownie wykorzystać jako dane wejściowe do ustawienia lub zresetowania aktualnie ustawionych zmiennych.

Innymi słowy, setanalizuje zmienne specyficzne dla powłoki, z których niektóre znajdują się na przykład w środowisku HOME. Dla kontrastu polecenia takie jak envi printenvspójrz na rzeczywistą zmienną środowiskową, z którą działa polecenie. Zobacz także to .


„W powłoce interaktywnej nie można odwoływać się do 1 $, 2 $ itd.” Czy istnieje bezpośrednie odniesienie do tego? Natknąłem się na dziwne przypadki, w których są one ustawione w interaktywnym środowisku powłoki i nie jestem pewien, czy byłoby to uważane za „niestandardowe”, czy nie.
user5359531,

@ user5359531 Szczerze mówiąc, nie jestem do końca pewien, skąd to wziąłem. Prawdopodobnie dlatego, że kiedy opublikowałem odpowiedź w 2017 roku, prawdopodobnie wspomniałem, że nie możesz zrobić czegoś takiego, 1="foo"ale później dowiedziałem się, że według definicji POSIX „słowo” (czyli nazwa obiektu takiego jak zmienna lub funkcja) nie może się rozpocząć z cyfrą (patrz pytanie, które opublikowałem na ten temat ). Parametry pozorne najwyraźniej stanowią wyjątek od tej reguły.
Sergiy Kolodyazhnyy

@ user5359531 Usunąłem część odpowiedzi, ponieważ nie jest ona szczególnie dokładna. Możesz odwoływać się $1, $2i tak dalej, w interaktywnej powłoce, w rzeczywistości odbywa się to za pomocą setpolecenia, często w celu obejścia/bin/sh ograniczenia braku macierzy. Dziękuję za zwrócenie mi na to uwagi. Zamierzam również edytować odpowiedź w ciągu najbliższych kilku dni, ponieważ wymaga ona trochę dodatkowego dopracowania i aktualizacji.
Sergiy Kolodyazhnyy

Dziękuję za wyjaśnienie. Problem mam jest to, że z condapo uruchomieniu source conda/bin/activate, to sprawdza, czy $1, $2itp, są ustawione, w celu ustalenia, czy został uruchomiony jako skrypt z argumentów lub nie. To kończy się zerwaniem w systemach, które z jakiegoś powodu mają te ustawione w środowisku interaktywnym. Mam nadzieję dowiedzieć się, czy to niestandardowe zachowanie jest wadą w systemie do ustawiania tych zmiennych w środowisku interaktywnym, czy w programie do używania ich do określania, czy zostało uruchomione jako skrypt.
user5359531

@ user5359531 Sugeruję, abyś zgłosił raport o błędzie do condaprogramistów lub każdego, kto jest oryginalnym autorem takiego skryptu, ponieważ sprawdzanie ${N}parametrów jest zdecydowanie niewłaściwą drogą. Istnieją pytania na ten sam temat tutaj i tutaj , a mniej więcej przenośny sposób polega na sprawdzeniu, czy ${0}jest taki sam jak nazwa skryptu, podczas gdy bashfaktycznie ma do tego celu zmienną środowiskową
Sergiy Kolodyazhnyy

4

Te $1, $2, $3, ..., ${10}, ${11}zmienne nazywane są parametry pozycyjne i są ujęte w sekcji ręcznego bash3.4.1

3.4.1 Parametry pozycji

Parametr pozycyjny jest parametrem oznaczonym jedną lub więcej cyframi, innymi niż pojedyncza cyfra 0. Parametry pozycyjne są przypisywane z argumentów powłoki podczas jej wywoływania i mogą być przypisane ponownie za pomocą wbudowanego polecenia set. Parametr pozycyjny N może być określany jako $ {N} lub jako $ N, gdy N składa się z jednej cyfry. Do parametrów pozycjonowania nie można przypisywać instrukcji przypisania. Wbudowane ustawienia i przesunięcia służą do ich ustawiania i wyłączania (zobacz Polecenia wbudowane w powłokę). Parametry pozycyjne są tymczasowo zastępowane, gdy wykonywana jest funkcja powłoki (patrz Funkcje powłoki).

Kiedy parametr pozycyjny składający się z więcej niż jednej cyfry jest rozwinięty, musi być ujęty w nawiasy klamrowe.

Jeśli chodzi o $?i $0, te specjalne parametry są omówione w następnej sekcji3.4.2

3.4.2 Parametry specjalne

Powłoka traktuje kilka parametrów specjalnie. Do tych parametrów można się jedynie odwoływać; przypisanie do nich jest niedozwolone.

...

?

($?) Rozwija się do statusu wyjścia ostatnio wykonywanego potoku pierwszego planu.

0

(0 USD) Rozwija się do nazwy powłoki lub skryptu powłoki. Jest to ustawiane przy inicjalizacji powłoki. Jeśli Bash zostanie wywołany z plikiem poleceń (zobacz Skrypty powłoki), $ 0 zostanie ustawione na nazwę tego pliku. Jeśli Bash jest uruchamiany z opcją -c (zobacz Wywoływanie Bash), wówczas $ 0 jest ustawiane na pierwszy argument po łańcuchu, który ma zostać wykonany, jeśli taki jest obecny. W przeciwnym razie zostanie ustawiona nazwa pliku używana do wywołania Bash, jak podano w argumencie zero.


4

$1, $2... są parametrami pozycyjnymi , nie są zmiennymi, a tym bardziej zmiennymi środowiskowymi.

Bourne jak powłoki terminologii $somethingnazywa parametrów ekspansji (obejmuje również ${something#pattern}i więcej w pewnych pocisków, takich jak ${array[x]}, ${param:offset},${x:|y} i wielu operatorów więcej rozszerzeń).

Istnieją różne rodzaje parametrów:

  • Zmienne podoba $foo,$PATH
  • parametry pozycyjne ( $1,$2 ... argumenty otrzymane przez twój skrypt)
  • Pozostałe parametry specjalne podoba $0, $-, $#, $*, $@, $$, $!, $?...

nazwy zmiennych w powłokach podobnych do Bourne'a muszą zaczynać się od jednego znaku alfabetycznego (dowolnego rozpoznawanego przez ustawienia regionalne lub ograniczonego do a-zA-Z w zależności od powłoki) i podkreślenia, a następnie zero lub więcej znaków alfanumerycznych lub podkreślników.

W zależności od powłoki zmienne mogą mieć różne typy (skalarne, tablicowe, mieszające) lub mieć określone atrybuty (tylko do odczytu, eksportowane, małe litery ...).

Niektóre z tych zmiennych są tworzone przez powłokę lub mają specjalne znaczenie dla powłoki (jak $OPTIND, $IFS, $_...)

Zmienne powłoki, które mają atrybut eksportu, są automatycznie eksportowane jako zmienne środowiskowe do poleceń wykonywanych przez powłokę.

Zmienna środowiskowa jest pojęciem odrębnym od zmiennych powłoki. Eksportowanie zmiennej powłoki nie jest jedynym sposobem przekazania zmiennej środowiskowej do wykonania polecenia.

VAR=foo
export VAR
printenv VAR

przekaże VARzmienną środowiskową do printenvpolecenia (które chcemy wydrukować jego zawartość), ale możesz także:

env VAR=foo printenv VAR

lub:

perl -e '$ENV{VAR}="foo"; exec "printenv", "VAR"'

na przykład.

Zmienne środowiskowe mogą mieć dowolną nazwę (mogą zawierać dowolny znak, ale =mogą być nawet puste). Nadanie zmiennej środowiskowej nazwy, która nie jest zgodna z nazwą zmiennej powłoki podobnej do Bourne'a, nie jest dobrym pomysłem, ale jest to możliwe:

$ env '#+%=whatever' printenv '#+%'
whatever

Powłoki będą mapować otrzymywane zmienne środowiskowe na zmienne powłokowe tylko dla tych zmiennych środowiskowych, których nazwy są poprawnymi zmiennymi powłokowymi (aw niektórych powłokach ignorują niektóre specjalne, takie jak$IFS ).

Tak więc, podczas gdy będziesz mógł przekazać 1zmienną środowiskową do polecenia:

$ env '1=whatever' printenv 1
whatever

Nie oznacza to, że wywołanie powłoki za pomocą tej zmiennej środowiskowej ustawiłoby wartość $1parametru:

$ env '1=whatever' sh -c 'echo "$1"' script-name foo bar
foo

3

Nie, są to parametry skryptu. Na przykład, jeśli wywołasz skrypt, na przykład:

mynicescript.sh one two three

następnie w skrypcie będą dostępne te parametry jako

$1 = one
$2 = two
$3 = three

a $ 0 to nazwa samego skryptu.

Więc kiedy jesteś poza skryptem, te zmienne nie są dostępne (oprócz 0 $, które wyświetla / bin / bash - sama powłoka).


„Więc kiedy jesteś poza skryptem, te zmienne nie są dostępne”. Co rozumiesz przez „poza skryptem” , ponieważ widzę wartości tych zmiennych w moim terminalu.
user7681202

2
@ user7681202: Które możesz zobaczyć w swoim terminalu? $0będzie wskazywał na twój aktualny proces terminalowy (prawdopodobnie bash) i $?jest po prostu kodem zakończenia ostatniego procesu.
Jesse_b

Próbowałem uruchomić gnome-terminalz argumentami ( gnome-terminal Hello World). Widziałem $0, ale nie widziałem $1i $2.
user7681202

@Jesse_b Dziękuję, dodałem zawartość 0 $ do odpowiedzi.
Jaroslav Kucera

1
@ user7681202 Gnome-terminal nie jest powłoką, jest emulatorem terminala (np. xterm, konsola itp.). Powłoka działa wewnątrz terminala i może to być bash / sh / zsh / tcsh i wiele innych. Skrypt jest plikiem wykonywalnym z odpowiednim nagłówkiem (jak #! / Bin / bash) i treścią interpretowalną przez powłokę określoną w masce. Zwykle używa przyrostka .sh
Jaroslav Kucera,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.