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):
- 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 .
export 3zmienić się$3w zmienną środowiskową. Nie możeszunset 3; i nie można przypisać$3nowej wartości za pomocą3=val.