Właśnie spotkałem kilka odpowiedzi, takich jak parsowanie pliku tekstowego z ogranicznikami ... używających konstrukcji:
while IFS=, read xx yy zz;do
echo $xx $yy $zz
done < input_file
gdzie IFS
zmienna jest ustawiona przed read
poleceniem.
Czytałem odniesienie do bash, ale nie mogę zrozumieć, dlaczego jest to legalne.
próbowałem
$ x="once upon" y="a time" echo $x $y
z wiersza polecenia bash, ale nic nie zostało powtórzone. Czy ktoś może wskazać mi, gdzie ta składnia jest zdefiniowana w odwołaniu, co pozwala na takie ustawienie zmiennej IFS? Czy to przypadek szczególny, czy mogę zrobić coś podobnego z innymi zmiennymi?
bash
shell
environment-variables
Mike Lippert
źródło
źródło
Odpowiedzi:
Jest pod gramatyką powłoki, proste polecenia (wyróżnienie dodane):
Możesz przekazać dowolną zmienną. Twój
echo
przykład nie działa, ponieważ zmienne są przekazywane do polecenia, a nie ustawione w powłoce. Powłoka rozszerza się$x
i$y
przed wywołaniem polecenia. Działa to na przykład:źródło
man bash
system ...Zdefiniowane zmienne stają się zmiennymi środowiskowymi w procesie rozwidlenia.
Jeśli uciekniesz
następnie bash najpierw rozwija
$A
się,""
a następnie uruchamiaOto poprawny sposób:
Zwróć uwagę na pojedyncze cytaty, w
bash -c
przeciwnym razie masz taki sam problem jak powyżej.Tak więc twój przykład pętli jest legalny, ponieważ wbudowane polecenie bash „czytaj” szuka IFS w zmiennych środowiskowych i znajduje
,
. W związku z tym,wydrukuje
TEST is and I is test
Wreszcie, jeśli chodzi o składnię, w pętli for oczekiwany jest ciąg znaków. Dlatego musiałem użyć odwróconych zwrotów, aby przekształcić je w polecenie. Jednak podczas gdy pętle oczekują składni poleceń, takich jak
IFS=, read xx yy zz
.źródło
A
zmienną zmienną bash rozwija się$A
do pustego ciągu, ale aby uniknąć pomyłek, nie użyłbym tego,""
ponieważ kod nie jest równoważnyA="b" echo ""
. Nie będzie argumentuecho
.man bash
Zmienne są rozwijane przed przypisaniem zmiennej. Z oczywistego powodu
var=x
działałoby to również w drugą stronę, alevar=$othervar
nie działało . Czyli twoja$x
jest potrzebna, zanim będzie dostępna. Ale to nie jest główny problem. Główny problem polega na tym, że wiersz poleceń może być modyfikowany tylko przez środowisko powłoki, ale przypisanie nie staje się częścią środowiska powłoki.Miksujesz z funkcjami: chcesz zastąpić wiersz poleceń, ale umieść definicję zmiennej w środowisku poleceń. Powłoka musi zastępować wiersz poleceń. Wywołane polecenie musi jawnie wykorzystywać środowisko. To, czy i jak to się robi, zależy od polecenia.
Zaletą tego użycia jest to, że można ustawić środowisko dla podprocesu bez wpływu na środowisko powłoki.
działa zgodnie z oczekiwaniami, ponieważ w takim przypadku obie funkcje są łączone: zamiana wiersza poleceń nie jest wykonywana przez powłokę wywołującą, ale przez powłokę podprocesu.
źródło
x="once upon" y="a time" eval 'echo $x $y'
wtedy, gdy nie jest zaangażowany żaden podproces, ponieważeval
jest wbudowany. Chyba odpowiedni cytat ze strony podręcznika brzmiThe environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments
. Biorąc pod uwagę przykład pytania, musi być tak, ponieważread
jest ono również wbudowane i działa ze zmienionym tymczasowo stanemIFS
.Komenda podasz jest inna, bo
$x
i$y
są rozszerzane , zanim wecho
seriach dowodzenia, więc ich wartości w bieżącej powłoce są wykorzystywane, a nie wartości, któreecho
byłyby widoczne w jego otoczeniu, gdyby spojrzeć.źródło
x
iy
są dla środowiska, któreecho
działa w, a nie środowisko, w którym argumentyecho
są rozszerzane. PonieważIFS=, read xx yy zz
cały ciąg jest odczytywany bezread
polecenia przez polecenie. Potem , że ciąg jest podzielony według wartościIFS
z odpowiednich elementów przypisanychxx
,yy
izz
.bash
najpierw analizuje podaną linię poleceń, rozpoznaje, że istnieją dwa przypisania zmiennych do środowiska nadchodzącej komendy, identyfikuje komendę do uruchomienia (echo
), rozszerza parametry znalezione w argumentach, a następnie uruchamia komendęecho
z rozszerzonymi argumentami.echo
nie byłem pewien, czy może „zobaczyć” zmienną, ponieważ jest to wbudowane polecenie i dlatego nie działa w podpowłoce, która mogłaby mieć własne środowisko. Ale wypróbowałem to zaeval
pomocą wbudowanego i rzeczywiście o tym wie. Np. Spróbuj,a=xyz eval 'echo $BASHPID $a; grep -z ^a /proc/$BASHPID/{,task/*}/environ'; echo $BASHPID $a
który pokazuje, żea
jest ustawiony tylko wewnątrz,eval
mimo że pid jest taki sam, a środowisko nie zmienia się podczas ewaluacji! (Aby uzyskać dostęp/proc
, musisz uruchomić to pod Linuksem.) Wygląda na to, że bash robi tutaj dodatkową magię.Idę po szerszy obraz „ dlaczego to jest legalne”
Odpowiedź: Aby móc wywoływać lub wywoływać program i do tego wywołania używaj tylko zmiennej z określoną zmienną.
Na przykład: masz parametr połączenia z bazą danych o nazwie „db_connection” i zwykle podajesz „test” jako nazwę testowego połączenia z bazą danych. W rzeczywistości możesz nawet ustawić go jako domyślny, którego nie musisz wtedy jawnie przekazywać. Czasami jednak chcesz pracować z bazą danych ci. Podajesz więc parametr jako „ci”, a następnie wywoływany program używa tego parametru bazy danych jako nazwy bazy danych, która ma być używana dla wszystkich wywołań bazy danych. W przypadku następnego uruchomienia, jeśli nie powtórzysz podejścia i po prostu wywołasz program, zmienna powróci do poprzedniej wartości domyślnej.
źródło
Możesz także użyć
;
. Zostanie to ocenione wcześniej, ponieważ jest to separator poleceń.źródło