Jak zapisać historię terminali do pliku z pliku bash?

7

Próbuję utworzyć skrypt bash, który zapisze historię terminala w pliku o nazwie hist.txt. history > hist.txtWydaje 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

Judy
źródło
3
Twoje pytanie jest trochę mylące. Co rozumiesz przez „nie wydaje się działać w pliku bash, ale działa dobrze, gdy jest wykonywany w wierszu poleceń”? Czy masz na myśli, że próbujesz zapisać historię poleceń z poziomu uruchamianego skryptu bash? Jak chcesz zapisać, jakie polecenia zostały wykonane przez skrypt? Sam skrypt jest w tym przypadku historią.
Stephen
6
A może chcesz wygenerować historię bash konkretnego użytkownika? Możesz po prostu odczytać ~/.bash_historyplik użytkownika .
Arronical
1
@ Uwaga elektroniczna, że ​​zadziała to tylko wtedy, gdy użytkownik użyje Bash jako powłoki, co nie zawsze ma miejsce.
1
@ p0llard Oczywiście wskoczyłem z założeniem, że tak jak w skrypcie Bash, będzie to Bash jako powłoka użytkownika, ale tak nie może być, jak powiedzieliście. Dobre szczegóły i tło w odpowiedzi BTW.
Arronical

Odpowiedzi:

11

Krótka odpowiedź

Uruchom skrypt za pomocą sourcelub .:

source ./script_name.sh

lub

. ./script_name.sh

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:

#!/bin/bash

cd /
ls

Jeśli to uruchomisz, otrzymasz wynik podobny do tego:

bin  boot  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

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.

sourceKomenda „do odczytu i wykonywania poleceń z argumentem pliku w bieżącym kontekście powłoki”, więc wszelkie polecenia, takie jak cdwewnątrz niego wpłynie na bieżącą sesję. Gdybyś uruchomił powyższy skrypt, przekazując go source, zobaczyłbyś, że skończy się w katalogu głównym po jego uruchomieniu.

W takim przypadku problem polega na tym, że historypolecenie udostępnia historię bieżącego kontekstu powłoki; kontekst powłoki, w którym skrypt działa bez użycia, sourcenie ma historii, więc nie zapisuje niczego w pliku wyjściowym. Jeśli sourcego użyjesz , uruchomi się we właściwym kontekście i będzie działał zgodnie z oczekiwaniami.

Uwaga: sourcejest wbudowanym poleceniem powłoki, a nie programu per se - w bash, sourcejest synonimem ., ale w niektórych muszli tylko .zadziała - Użyłem sourcew tej odpowiedzi, ponieważ jest to łatwiejsze do odczytania niż ., ale dla maksymalnej kompatybilności, .powinien być użytym.


źródło
Bardzo ciekawa lektura. Zawsze zastanawiałem się nad „brakującymi” poleceniami historii, teraz już wiem dlaczego. Dzięki!
Tico
10

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 historypolecenie 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:

#!/bin/bash
echo "$var"

Teraz ustaw $varcoś i uruchom skrypt:

$ var="foo"
$ foo.sh
VAR: 

Następnie najpierw wyeksportuj zmienną:

$ var="foo"
$ export var
$ foo.sh
VAR: foo

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:

$ cat foo.sh
#!/bin/bash
echo "HISTFILE: $HISTFILE"
$ ./foo.sh
HISTFILE:
$ echo $HISTFILE
/home/terdon/.bash_history

Jak widać w powyższym przykładzie, zmienna HISTFILEjest ustawiana w mojej normalnej sesji powłoki, ale jest pusta po uruchomieniu skryptu.

Aby uzyskać historię, masz kilka opcji:

  1. Wartość domyślna HISTFILEto $HOME/.bash_history. Jeśli tego nie zmieniłeś, możesz po prostu uruchomić to polecenie w skrypcie:

    cat "$HOME/.bash_history" > history
  2. Możesz przekazać $HISTFILEzmienną do skryptu i catże:

    #!/bin/bash
    cat "$1" > history

    Zapisz powyższe jako foo.shi uruchom tak:

    ./foo.sh "$HISTORY"
  3. Upewnij się, że zmienna jest eksportowana. Dodaj ten wiersz do swoich ~/.bash_profile(jeśli istnieje) lub ~/.profile(jeśli ~/.bash_profilenie istnieje) plików:

    export HISTFILE

    Następnie wyloguj się i zaloguj ponownie, a powinieneś być w stanie uruchomić history > hist.txtze skryptu zgodnie z oczekiwaniami. Wynika to z faktu, export VARże „udostępnia $ VAR skorupom potomnym”. W praktyce oznacza to, że wartość HISTFILEzostanie odziedziczona przez nieinteraktywną powłokę używaną do uruchamiania skryptu.

    Teraz, gdy HISTFILEzostanie ustawiony, nie został odczytany przez powłokę uruchamiającą skrypt. Aby więc działał, musisz go history -rnajpierw przeczytać . Cały skrypt wyglądałby tak:

    $!/bin/bash
    history -r
    history > hist.txt

    Alternatywnie, po prostu wyeksportuj go ręcznie przed uruchomieniem skryptu:

    $ export HISTFILE

    Ale nadal będziesz musiał to zrobić history -rw skrypcie.

  4. Możesz to sourcezrobić zgodnie z sugestią @ p0llard .

terdon
źródło