Zmienne środowiskowe a parametry pozycyjne
Zanim zaczniemy omawiać $INTEGER
typy zmiennych, musimy zrozumieć, czym one naprawdę są i czym różnią się od zmiennych środowiskowych. Zmienne takie jak $INTEGER
nazywane są parametrami pozycyjnymi. Jest to opisane w standardzie POSIX (Portable Operating System Interface), sekcja 2.1 (wyróżnienie moje):
- 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 $HOME
i $PATH
są 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 Hello
i World
, ponieważ są to parametry pozycyjne dla echo
- rzeczy, na których chcesz echo
operować. I echo
jest 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 Hello
iWorld
to 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 HOME
lub PATH
mają określony format, konkretne znaczenie i będą oznaczały to samo dla każdego programu. HOME
zmienna będzie oznaczać to samo dla zewnętrznego narzędzia, takiego jak dla /usr/bin/find
twojej 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 poleceniaUID
zmiennej ś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-terminal
po uruchomieniu spojrzy na twoją SHELL
zmienną ś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 ksh
zamiast tego odrodzi się bash
. To także przykład wykorzystania środowiska przez programy. Gdybym wyraźnie powiedzieć gnome-terminal
ze -e
uruchomić 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, main
która zazwyczaj wygląda
int main(int argc, char **argv)
, gdzie argc
jest liczba argumentów wiersza polecenia i argv
efektywnie tablica parametrów wiersza polecenia, a następnie jest environ
funkcja (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 PATH
któ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
, $2
i 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 bash
powł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 -c
opcją mogą korzystać z argumentów $1
i $2
argumentó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ż sh
tam użyłem , ponieważ małe dziwactwo -c
opcji 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 bash
z własnymi parametrami pozycyjnymi, ale te parametry pozycyjne stały się parametrami do echo
i stat
. I każdy program rozumie to na swój sposób. Gdybyśmy podali stat
ciąg Hello World
i nie ma pliku Hello World
, spowodowałby to błąd; bash
traktuje go jak zwykły ciąg, ale stat
oczekuje, że będzie to istniejąca nazwa pliku. Natomiast wszystkie programy zgodziłyby się, że zmienna środowiskowa HOME
jest 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=value
z 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ą shift
polecenia.
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
set
Rozkaz, 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, set
analizuje zmienne specyficzne dla powłoki, z których niektóre znajdują się na przykład w środowisku HOME
. Dla kontrastu polecenia takie jak env
i printenv
spójrz na rzeczywistą zmienną środowiskową, z którą działa polecenie. Zobacz także to .
export 3
zmienić się$3
w zmienną środowiskową. Nie możeszunset 3
; i nie można przypisać$3
nowej wartości za pomocą3=val
.