Zgodnie z instrukcją Bash zmienna środowiskowa BASH_COMMAND
zawiera
Komenda aktualnie wykonywana lub planowana do wykonania, chyba że powłoka wykonuje komendę w wyniku pułapki, w którym to przypadku jest to komenda wykonywana w chwili pułapki.
Pomijając tę narożną wielkość liter, jeśli dobrze rozumiem, oznacza to, że kiedy wykonuję polecenie, zmienna BASH_COMMAND
zawiera to polecenie. Nie jest absolutnie jasne, czy zmienna ta jest rozbrojona po wykonaniu polecenia (tj. Jest dostępna tylko podczas wykonywania polecenia, ale nie później), choć można argumentować, że ponieważ jest to „polecenie aktualnie wykonywane lub wkrótce wykonywane” , to nie polecenie zostało właśnie wykonane.
Ale sprawdźmy:
$ set | grep BASH_COMMAND=
$
Pusty. Spodziewałbym się zobaczyć, BASH_COMMAND='set | grep BASH_COMMAND='
a może po prostu BASH_COMMAND='set'
, ale pusty mnie zaskoczył.
Spróbujmy czegoś innego:
$ echo $BASH_COMMAND
echo $BASH_COMMAND
$
To ma sens. Wykonuję polecenie, echo $BASH_COMMAND
więc zmienna BASH_COMMAND
zawiera ciąg echo $BASH_COMMAND
. Dlaczego tym razem zadziałało, ale nie wcześniej?
Zróbmy to jeszcze set
raz:
$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$
Więc poczekaj. To było ustawione, że kiedy wykonywane echo
polecenie, a on nie był wyłączony później. Ale kiedy wykonałem set
ponownie, BASH_COMMAND
nie został ustawiony na set
polecenie. Bez względu na to, jak często wykonuję set
polecenie tutaj, wynik pozostaje taki sam. Czy zmienna jest ustawiona podczas wykonywania echo
, ale nie podczas wykonywania set
? Zobaczmy.
$ echo Hello AskUbuntu
Hello AskUbuntu
$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$
Co? Więc zmienna została ustawiona, kiedy wykonałem echo $BASH_COMMAND
, ale nie kiedy wykonałem echo Hello AskUbuntu
? Jaka jest teraz różnica? Czy zmienna jest ustawiona tylko wtedy, gdy bieżące polecenie faktycznie zmusza powłokę do oceny zmiennej? Spróbujmy czegoś innego. Może tym razem jakieś zewnętrzne polecenie, a nie wbudowane bash, dla odmiany.
$ /bin/echo $BASH_COMMAND
/bin/echo $BASH_COMMAND
$ set | grep BASH_COMMAND=
BASH_COMMAND='/bin/echo $BASH_COMMAND'
$
Hmm, ok ... znowu, zmienna została ustawiona. Czy moje obecne przypuszczenie jest prawidłowe? Czy zmienna jest ustawiana tylko wtedy, gdy należy ją ocenić? Czemu? Czemu? Z powodów wydajnościowych? Spróbujmy jeszcze raz. Spróbujemy grepować $BASH_COMMAND
w pliku, a ponieważ $BASH_COMMAND
powinien zawierać grep
polecenie, grep
powinien grep dla tego grep
polecenia (tj. Dla siebie). więc stwórzmy odpowiedni plik:
$ echo -e "1 foo\n2 grep\n3 bar\n4 grep \$BASH_COMMAND tmp" > tmp
$ grep $BASH_COMMAND tmp
grep: $BASH_COMMAND: No such file or directory
tmp:2 grep <-- here, the word "grep" is RED
tmp:4 grep $BASH_COMMAND tmp <-- here, the word "grep" is RED
tmp:2 grep <-- here, the word "grep" is RED
tmp:4 grep $BASH_COMMAND tmp <-- here, the word "grep" is RED
$ set | grep BASH_COMMAND=
BASH_COMMAND='grep --color=auto $BASH_COMMAND tmp'
$
OK, ciekawe. Polecenie grep $BASH_COMMAND tmp
zostało rozszerzone do grep grep $BASH_COMMAND tmp tmp
(zmienna jest rozwinięta tylko raz, oczywiście), więc poszukałem grep
, raz w pliku, $BASH_COMMAND
który nie istnieje, i dwa razy w pliku tmp
.
P1: Czy moje obecne założenie jest prawidłowe, że:
BASH_COMMAND
jest ustawiany tylko wtedy, gdy polecenie próbuje to ocenić; i- to jest nie rozbroić po wykonaniu polecenia, choć opis może doprowadzić nas do przekonania, tak?
P2: Jeśli tak, dlaczego? Wydajność? Jeśli nie, jak inaczej można wyjaśnić zachowanie w powyższej sekwencji poleceń?
P3: Na koniec, czy jest jakiś scenariusz, w którym ta zmienna mogłaby być rzeczywiście użytecznie użyta? W rzeczywistości próbowałem użyć go w $PROMPT_COMMAND
celu przeanalizowania wykonywanego polecenia (i zrobić kilka rzeczy w zależności od tego), ale nie mogę, ponieważ jak tylko $PROMPT_COMMAND
wykonam wewnątrz siebie polecenie, aby spojrzeć na zmienną $BASH_COMMAND
, zmienną pobiera zestawy do tego polecenia. Nawet jeśli robię to MYVARIABLE=$BASH_COMMAND
na samym początku $PROMPT_COMMAND
, MYVARIABLE
zawiera ciąg MYVARIABLE=$BASH_COMMAND
, ponieważ przypisanie jest również poleceniem. (To pytanie nie dotyczy tego, w jaki sposób mogę uzyskać bieżące polecenie w ramach $PROMPT_COMMAND
wykonania. Wiem, że istnieją inne sposoby).
To trochę tak, jak w przypadku zasady nieoznaczoności Heisenberga. Po prostu obserwując zmienną, zmieniam ją.
źródło
bash
guru über-guru.Odpowiedzi:
Odpowiadając na trzecie pytanie: oczywiście można go w znaczący sposób wykorzystać w sposób, w jaki instrukcja Bash wyraźnie wskazuje - w pułapce, np .:
źródło
$BASH_COMMAND
rzeczywiście można go sensownie wykorzystać nawet w kontekstach innych niż pułapka. Jednak opisywane zastosowanie jest prawdopodobnie najbardziej typowe i proste. Więc twoja odpowiedź, i ta autorstwa DocSalvager, odpowiedzą najlepiej na mój trzeci kwartał , a to było dla mnie najważniejsze. Co do Q1 i Q2, jak wskazują @zwets, te rzeczy są niezdefiniowane. Może być tak, że$BASH_COMMAND
podana jest tylko wartość, jeśli jest dostępna, dla wydajności - w przeciwnym razie niektóre dziwne wewnętrzne warunki programu mogą prowadzić do takiego zachowania. Kto wie?$BASH_COMMAND
ustawienie zawsze, wymuszając ocenę$BASH_COMMAND
przed każdym poleceniem. Aby to zrobić, możemy użyć pułapki DEBUG, która jest wykonywana przed każdym pojedynczym poleceniem (wszystkimi em). Jeśli wydamy np.,trap 'echo "$BASH_COMMAND" > /dev/null' DEBUG
Wtedy$BASH_COMMAND
zawsze będzie oceniany przed każdym poleceniem (i przypisywana jest jego wartość$COMMAND
). Więc jeśli wykonam,set | grep BASH_COMMAND=
gdy pułapka jest aktywna ... co wiesz? Teraz wynik jestBASH_COMMAND=set
, zgodnie z oczekiwaniami :)Teraz, kiedy Q3 zostało już odebrane (poprawnie, moim zdaniem:
BASH_COMMAND
jest przydatne w pułapkach i prawie nigdzie indziej), dajmy szansę Q1 i Q2.Odpowiedź na pytanie 1 brzmi: poprawność twojego założenia jest nierozstrzygalna. Nie można ustalić prawdziwości żadnego z punktów, ponieważ pytają o nieokreślone zachowanie. Zgodnie ze specyfikacją wartość parametru
BASH_COMMAND
jest ustawiona na tekst polecenia na czas wykonywania tego polecenia. Specyfikacja nie określa, jaka powinna być jej wartość w żadnej innej sytuacji, tj. Gdy nie jest wykonywane żadne polecenie. Może mieć dowolną wartość lub nie mieć jej wcale.Odpowiedź na pytanie 2 „Jeśli nie, jak inaczej można wyjaśnić zachowanie w powyższej sekwencji poleceń?” następnie następuje logicznie (choć nieco pedantycznie): tłumaczy to fakt, że wartość nie
BASH_COMMAND
jest zdefiniowana. Ponieważ jego wartość jest niezdefiniowana, może mieć dowolną wartość, co dokładnie pokazuje sekwencja.Postscriptum
Jest jeden punkt, w którym myślę, że rzeczywiście trafiasz na słabość w specyfikacji. To tam mówisz:
Sposób, w jaki czytam stronę podręcznika użytkownika bash, nieco kursywą jest nieprawdziwy. Sekcja
SIMPLE COMMAND EXPANSION
wyjaśnia, w jaki sposób najpierw odkładane są przypisania zmiennych w wierszu poleceń, a następnieTo sugeruje mi, że przypisania zmiennych nie są poleceniami (i dlatego są zwolnione z pokazywania się w
BASH_COMMAND
), jak w innych językach programowania. To wyjaśniałoby również, dlaczego nie ma liniiBASH_COMMAND=set
na wyjściuset
, coset
zasadniczo jest składniowym „znacznikiem” dla przypisania zmiennej.OTOH, w ostatnim akapicie tego rozdziału jest napisane
... co sugeruje inaczej, a przypisania zmiennych są również poleceniami.
źródło
set
BASH_COMMAND='set'
set
polecenia . Dlatego zgodnie ze specyfikacjami powinno działać. Czy więc implementacja nie jest wiernie zgodna ze specyfikacjami, czy też źle ją rozumiem? Znalezienie odpowiedzi na to pytanie jest swego rodzaju celem pytania pierwszego. +1 za twójset
.set
nie jest „poleceniem”. Tak jak=
nie jest to „polecenie”. Przetwarzanie tekstu następującego / otaczającego te tokeny może mieć zupełnie inną logikę niż przetwarzanie „polecenia”.set
nie liczy się to jako „polecenie”. Nie$BASH_COMMAND
sądziłbym, że w wielu okolicznościach okaże się to tak nieokreślone.Pomysłowe zastosowanie dla $ BASH_COMMAND
Ostatnio odkryłem to imponujące zastosowanie $ BASH_COMMAND we wdrażaniu funkcji podobnej do makra.
Poprzedni artykuł autora zapewnia również dobre tło podczas wdrażania techniki za pomocą DEBUGI
trap
. Zostałtrap
wyeliminowany w ulepszonej wersji.źródło
$BASH_COMMAND
można go sensownie wykorzystać w kontekście innym niżtrap
. Cóż to za użytek! Używanie go do wdrażania makropoleceń w bash - kto by pomyślał, że to możliwe? Dzięki za wskaźnik.Pozornie powszechne zastosowanie pułapki ... debugowanie polega na poprawianiu tytułów pojawiających się w oknie dialogowym (^ A ”) podczas korzystania z„ screen ”.
Próbowałem uczynić „screen”, „windowlist” bardziej użytecznym, więc zacząłem znaleźć artykuły odnoszące się do „trap… debugowania”.
Odkryłem, że metoda wykorzystująca PROMPT_COMMAND do wysłania „pustej sekwencji tytułowej” nie działała tak dobrze, więc wróciłem do metody pułapki… debugowania.
Oto jak to zrobić:
1 Powiedz „screen”, aby szukał sekwencji ucieczki (włącz ją), umieszczając „shelltitle” $ | bash: '”w„ $ HOME / .screenrc ”.
2 Wyłącz propagację pułapki debugowania w podpowłokach. Jest to ważne, ponieważ jeśli jest włączone, wszystko się psuje, użyj: „set + o funkrace”.
3 Wyślij sekwencję zmiany znaczenia dla „ekranu” do interpretacji: pułapka „printf” \ ek $ (data +% Y% m% d% H% M% S) $ (whoami) @ $ (nazwa hosta): $ (pwd) $ {BASH_COMMAND} \ e \ "" „DEBUG”
To nie jest idealne, ale pomaga, i możesz użyć tej metody, aby dosłownie dodać do tytułu dosłownie wszystko, co chcesz
Zobacz następujący „windowlist” (5 ekranów):
Num Nazwa Flagi
1 bash: 20161115232035 mcb @ ken007: / home / mcb / ken007 RSYNCCMD = "sudo rsync" myrsync.sh -R -r "$ {1}" "{BACKUPDIR} $ {2: +" / $ {2} " } "$ 2 bash: 20161115230434 mcb @ ken007: / home / mcb / ken007 ls --color = auto -la 3 bash: 20161115230504 mbb @ ken007: / home / mcb / ken007 cat bin / psg.sh 4 bash: 20161115222415 mcb @ ken007: / home / mcb / ken007 ssh ken009 5 bash: 20161115222450 mcb @ ken007: / home / mcb / ken007 mycommoncleanup $
źródło