Próbuję utworzyć skrypt bash, który zapisze historię terminala w pliku o nazwie hist.txt. history > hist.txt
Wydaje się, że używanie nie działa w skrypcie bash, ale działa dobrze, gdy jest wykonywane w wierszu poleceń.
Wszelkie wskazówki są mile widziane.
Dziękuję Judy
~/.bash_history
plik użytkownika .Odpowiedzi:
Krótka odpowiedź
Uruchom skrypt za pomocą
source
lub.
:lub
Ta ostatnia jest nieco bardziej kompatybilna w różnych powłokach.
Długa odpowiedź
To pytanie podkreśla ważną kwestię: skrypty powłoki są uruchamiane w ich własnym kontekście. Aby zobaczyć, co to oznacza, rozważ następujący skrypt powłoki:
Jeśli to uruchomisz, otrzymasz wynik podobny do tego:
Zauważysz jednak, że po uruchomieniu skryptu nadal znajdujesz się w dowolnym katalogu, w którym byłeś przed uruchomieniem:
cd /
wnętrze skryptu tak naprawdę nie wpłynęło na twoją sesję - wpłynęło tylko na kontekst, w którym skrypt był uruchomiony, w którym jest tworzony w celu uruchomienia skryptu i niszczony po powrocie.source
Komenda „do odczytu i wykonywania poleceń z argumentem pliku w bieżącym kontekście powłoki”, więc wszelkie polecenia, takie jakcd
wewnątrz niego wpłynie na bieżącą sesję. Gdybyś uruchomił powyższy skrypt, przekazując gosource
, zobaczyłbyś, że skończy się w katalogu głównym po jego uruchomieniu.W takim przypadku problem polega na tym, że
history
polecenie udostępnia historię bieżącego kontekstu powłoki; kontekst powłoki, w którym skrypt działa bez użycia,source
nie ma historii, więc nie zapisuje niczego w pliku wyjściowym. Jeślisource
go użyjesz , uruchomi się we właściwym kontekście i będzie działał zgodnie z oczekiwaniami.Uwaga:
source
jest wbudowanym poleceniem powłoki, a nie programu per se - w bash,source
jest synonimem.
, ale w niektórych muszli tylko.
zadziała - Użyłemsource
w tej odpowiedzi, ponieważ jest to łatwiejsze do odczytania niż.
, ale dla maksymalnej kompatybilności,.
powinien być użytym.źródło
Przede wszystkim pamiętaj, że Twoja historia jest już w pliku. Jeśli uruchamiasz bash, jego nazwa to zwykle
~/.bash_history
. Mówiąc dokładniej, jest to wszystko, na co ustawiłeś zmiennąHISTFILE
. Jeśli chcesz skopiować go do innego pliku, po prostu uruchomcat "$HISTFILE" > hist.txt
Teraz, dlaczego to
history
polecenie nie działa w skrypcie powłoki bash, to dlatego, że skrypty są uruchamiane w nieinteraktywnej powłoce podrzędnej bieżącej sesji powłoki. Powłoki potomne nie dziedziczą całego środowiska macierzystego (a więc nie wszystkich ustawionych zmiennych), tylko zmienne, które zostały wyeksportowane. Aby to zilustrować, poniższy skrypt wyśle echo wartości zmiennej$var
:Teraz ustaw
$var
coś i uruchom skrypt:Następnie najpierw wyeksportuj zmienną:
Jak widać, po wyeksportowaniu zmiennej jest ona dostępna dla powłok potomnych.
Jak wspomniałem wcześniej, historia jest przechowywana w pliku wskazywanym przez zmienną
$HISTFILENAME
. Ponieważ nie jest to domyślnie eksportowane, nie jest ustawione podczas uruchamiania skryptu:Jak widać w powyższym przykładzie, zmienna
HISTFILE
jest ustawiana w mojej normalnej sesji powłoki, ale jest pusta po uruchomieniu skryptu.Aby uzyskać historię, masz kilka opcji:
Wartość domyślna
HISTFILE
to$HOME/.bash_history
. Jeśli tego nie zmieniłeś, możesz po prostu uruchomić to polecenie w skrypcie:Możesz przekazać
$HISTFILE
zmienną do skryptu icat
że:Zapisz powyższe jako
foo.sh
i uruchom tak:Upewnij się, że zmienna jest eksportowana. Dodaj ten wiersz do swoich
~/.bash_profile
(jeśli istnieje) lub~/.profile
(jeśli~/.bash_profile
nie istnieje) plików:Następnie wyloguj się i zaloguj ponownie, a powinieneś być w stanie uruchomić
history > hist.txt
ze skryptu zgodnie z oczekiwaniami. Wynika to z faktu,export VAR
że „udostępnia $ VAR skorupom potomnym”. W praktyce oznacza to, że wartośćHISTFILE
zostanie odziedziczona przez nieinteraktywną powłokę używaną do uruchamiania skryptu.Teraz, gdy
HISTFILE
zostanie ustawiony, nie został odczytany przez powłokę uruchamiającą skrypt. Aby więc działał, musisz gohistory -r
najpierw przeczytać . Cały skrypt wyglądałby tak:Alternatywnie, po prostu wyeksportuj go ręcznie przed uruchomieniem skryptu:
Ale nadal będziesz musiał to zrobić
history -r
w skrypcie.Możesz to
source
zrobić zgodnie z sugestią @ p0llard .źródło