Historia BASH obcięta do 500 linii przy każdym logowaniu

22

Z jakiegoś powodu nie mogę zmusić mojego systemu do zachowania historii BASH po ponownym uruchomieniu. Oto odpowiednie sekcje mojego ~/.bashrc:

shopt -s histappend
PROMPT_COMMAND='history -a; updateWindowTitle'
export HISTCONTROL=ignoredups
export HISTSIZE=9999
export HISTFILESIZE=999999
export HISTFILE="$HOME/.bash_history"

O ile mogę powiedzieć, są to wszystkie niezbędne opcje ( wiem, że kiedyś mogłem przechowywać historię na wielu restartach bez tych wszystkich w przeszłości). Jednak pomimo dodania tych opcji kilka restartów temu, nadal tracę większość historii po ponownym uruchomieniu. Nie jest pusty, ale nie ma linii 9999, które miałem przed ponownym uruchomieniem.

Zanim ktokolwiek narzeka, tak, przeczytałem te pytania. Wdrożyłem niektóre z ich sugestii wymienionych powyżej, pozostałe były albo nieprzydatne, albo nieistotne:

Jeśli nie ma szans, że mogą tam znajdować się inne odpowiednie polecenia, możesz zobaczyć moją całość ~/.bashrc tutaj .

Więc czego mi brakuje? Dlaczego moja historia nie jest zapisana? Jeśli ktoś uważa, że ​​inny plik może być odpowiedni, daj mi znać, a ja go opublikuję. Sprawdziłem, uruchamiając grep -i hist \.*w moim, $HOMEktóry pokazał, że jedynym odpowiednim .plikiem zawierającym ciąg histlub HISTbył .bashrc.

Używam Linux Mint Debian Edition, GNU bash, wersja 4.2.36 (1) -release (x86_64-pc-linux-gnu) i mój ulubiony emulator terminala (jeśli jest to istotne) terminator.


AKTUALIZACJA:

Podążając za sugestią @ mpy w komentarzach, zmieniłem ~/.bashrcustawienie HISTFILE=~/bash_historyna przeciwne do domyślnego ~/.bash_historyi wydaje się, że to rozwiązuje problem interaktywnych powłok . Powłoki logowania nadal wyświetlają to samo zachowanie, a historia jest obcinana w 500wierszach. Jednak HISTw odpowiednich plikach nie ma powiązanych zmiennych:

$ for f in /etc/profile ~/.profile ~/.bash_profile ~/.bash_login; do \
   echo -ne "$f :"; echo `grep HIST $f`; \
done
/etc/profile :
/home/terdon/.profile :grep: /home/terdon/.profile: No such file or directory
/home/terdon/.bash_profile :grep: /home/terdon/.bash_profile: No such file or directory
/home/terdon/.bash_login :grep: /home/terdon/.bash_login: No such file or directory
$ grep -r HIST /etc/profile.d/  <-- returns nothing

Więc dlaczego jest ustawienie HISTSIZEi HISTFILESIZEw ~/.bashrcnie na tyle, chyba że wyraźnie ustawić $HISTFILEsię do czegoś innego niż domyślny ~/.bash_history?

terdon
źródło
Czy jesteś właścicielem .bash_history lub root? Czy ls -l .bash_history
Adnan Bhatti
1
@MSStp tak, jest własnością mnie. Dzięki za sugestię, ale nie rozumiem, jak to może być problem z uprawnieniami, albo mam do niej dostęp do odczytu / zapisu, albo nie. Ponieważ pewna historia została ocalona, ​​ja oczywiście. Gdyby bash miał ustawienie, które powodowało problemy, gdy ten plik nie jest własnością użytkownika, narzekałby lub cała funkcja historii nie działałaby.
terdon
kiedy wykonujesz historypolecenie, wynik, który widzisz, jest identyczny z tym, co widzisz, działającym cat .bash_history, innym niż numery linii? Mam na myśli, czy historyznaczniki czasu listy poleceń lub inne informacje? Pytam dlatego, że jeśli widzisz te ezoteryczne rzeczy, oznacza to, że istnieje inny moduł / funkcja / program, który psuje się z historią powłoki i zła lub błędna wersja tego, co jest, może powodować ci smutek .
MelBurslan
@Mel_Burslan tak, to jest to samo, jedyną różnicą są numery linii.
terdon
2
Ok, nieco dziwna sugestia, ale jest to również problem związany ze zużyciem ;): Wypróbuj inny plik jako HISTFILE, a nie domyślny ~/.bash_history. Bardzo skonstruowane wyjaśnienie: Zakładam, że bash jest domyślną powłoką, więc po uruchomieniu systemu powłoka nieinteraktywna jest rodzicem sesji X (zakładam również, że używasz X), który nie będzie wiedział nic o opcji histappend (ponieważ .bashrc jest tylko czytane przez interaktywne powłoki), więc tak długo, jak ta macierzysta powłoka działa, wszystko jest w porządku, ale po zakończeniu (tj. zatrzymaniu systemu) zastąpi ~/.bash_history(co jest domyślne) i
popsunie

Odpowiedzi:

17

Problem w rzeczywistości sprowadza się do różnych zachowań powłok logowania i bez logowania. Ustawiłem zmienne, które kontrolują historię w moim ~/.bahsrc. Ten plik nie jest odczytywany po uruchomieniu powłoki logowania, jest odczytywany tylko przez interaktywne powłoki niezalogowane (z man bash):

Kiedy bash jest wywoływany jako interaktywna powłoka logowania lub jako nieinteraktywna powłoka z --loginopcją, najpierw czyta i wykonuje polecenia z pliku /etc/profile, jeśli plik istnieje. Po przeczytaniu tego pliku, szuka ~ / .bash_profile, ~/.bash_logini ~/.profile, w tej kolejności, a odczytuje i wykonuje polecenia z pierwszego, który istnieje i jest czytelny. --noprofileOpcja może być stosowany, gdy powłoka jest uruchamiany w celu zahamowania tego zachowania.

[. . . ]

Po uruchomieniu interaktywnej powłoki, która nie jest powłoką logowania, bash czyta i wykonuje polecenia z ~ / .bashrc, jeśli plik istnieje. Można temu zapobiec, używając opcji --norc. Opcja pliku --rcfile zmusi bash do odczytu i wykonywania poleceń z pliku zamiast ~ / .bashrc.

Dlatego za każdym razem, gdy logowałem się, upuszczałem na tty lub korzystałem z ssh, .historyplik był obcinany, ponieważ nie ustawiłem go również we właściwym rozmiarze ~/.profile. W końcu zdałem sobie z tego sprawę i po prostu ustawiłem zmienne ~/.profile tam, gdzie należą , zamiast~/.bashrc

Dlatego ~/.historyzostałem obcięty, ponieważ ustawiłem tylko zmienne HISTORY w pliku odczytywanym przez interaktywne powłoki bez logowania i dlatego za każdym razem, gdy uruchamiam inny typ powłoki, zmienne byłyby ignorowane i plik byłby cięty odpowiednio.

terdon
źródło
Bardzo dobry punkt, dziękuję za udostępnienie! Nie zgadzam się jednak z tym: ten plik nie jest odczytywany po uruchomieniu powłoki logowania, jest odczytywany tylko przez powłoki interaktywne. Ponieważ powłoka logowania może być również interaktywna. W przeciwnym razie cały mechanizm historii nie miałby sensu. IMHO .bashrcnie jest odczytywany przez (nieinteraktywne powłoki logujące LUB).
mpy
@ mpy Rzeczywiście przepraszam, miałem na myśli interaktywne powłoki bez logowania. Odpowiedź edytowana.
terdon
1
@terdon, powszechnym idiomem jest to, że interaktywne opcje powłoki nie wchodzą w ~ / .profile lub ~ / .bash_profile. Interaktywne opcje powłoki są umieszczone w ~ / .bashrc. Aby uniknąć konieczności utrzymywania ustawień w dwóch miejscach, na górze ~ / .bash_profile można umieścić następujące polecenia: export BASH_ENV=~/.bashrc ; if [ -f ~/.bashrc ]; then . ~/.bashrc; fi... i na górze ~ / .bashrc zaznaczyć, aby upewnić się, że naprawdę działasz interaktywnie: [ -z "$PS1" ] && return... Oczywiście to tylko idiom.
Noah Spurrier
1
@NoahSpurrier BASH_ENVnie jest istotny, dotyczy tylko nieinteraktywnych powłok. Jeśli chodzi o „idiom”, jest to coś, co rozpoczął Debian iz którym osobiście się nie zgadzam. Często mam opcje graficzne ( xseti tym podobne) w moim .bashrc i nie chcę, aby były one aktywne, gdy uruchamiam powłoki logowania od tty lub przez ssh. Chcę, aby mój .profile i .bashrc były osobne. Wiele (choć nie wszystkie) menedżerów logowania źródłowych .profile podczas logowania, więc zmienne globalne najlepiej ustawić tam, gdzie będą odczytywane tylko raz, a nie przy każdym otwarciu terminala.
terdon
1
@WilsonF tak. Pliki są odczytywane sekwencyjnie, a pliki osobiste ( ~/.profilelub ~/.bashrc) są odczytywane na końcu. Wszystko, co zostanie w nich ustawione, będzie miało pierwszeństwo przed ustawieniami globalnymi. Masz całkowitą rację, nie powinieneś ustawiać tych zmiennych /etc/bash.bashrc. Zamiast tego użyj ~/.profile(lub ~/.bash_profile).
terdon
11

Moją sugestią jest użycie innego pliku, a HISTFILEnie domyślnego ~/.bash_history.

Chociaż nie mam analitycznego wyjaśnienia, postaram się nakreślić, co doprowadziło mnie do tej sugestii: jeśli użyjesz bashjako domyślnej powłoki (logowania), a także użyjesz X(co jest bardzo prawdopodobne), masz działającą bashinstancję zaraz po (graficznym ) Zaloguj sie:

systemd
 ...
  |-login
  |   `-bash      <<====
  |       `-slim
  |           |-X -nolisten tcp vt07 -auth /var/run/slim.auth
  |           |  `-{X}
  |           `-fluxbox
  |               `-xterm -bg black -fg white
  |                   `-bash
 ...

Myślę, że to wystąpienie jest powłoką logowania, więc nie odczytuje twojej, ~/.bashrca zatem nie będzie wiedzieć o tej histappendopcji:

man bash (1) : Gdy uruchamiana jest interaktywna powłoka, która nie jest powłoką logowania , bash czyta i wykonuje polecenia z /etc/bash.bashrc i ~ / .bashrc, jeśli te pliki istnieją. (...)

Tak długo, jak działa ta „nadrzędna powłoka”, wszystko jest w porządku, ale po jej zakończeniu (tj. Zatrzymaniu systemu) będzie ona nadpisywać ~/.bash_history(ponieważ jest to wartość domyślna) i popsunie historię lub przycina ją w systemie, aby zacząć (ponownie domyślnie) 500 linie. (A może oba ...)

Uderza mnie również to, że nie wystarczy dołączyć konfigurację historii ~/.bashrc, ponieważ nie powinna to być tak rzadka konfiguracja. Nie mam na to wytłumaczenia.


Jeśli chodzi o problem polegający na tym, że „Powłoki logowania nadal wyświetlają to samo zachowanie”, możesz spróbować dołączyć konfigurację historii również do ~/.bash_profile:

man bash (1) : Kiedy bash jest wywoływany jako interaktywna powłoka logowania lub jako nieinteraktywna powłoka z opcją --login, najpierw czyta i wykonuje polecenia z pliku / etc / profile, jeśli plik ten istnieje. Po odczytaniu tego pliku szuka ~ / .bash_profile, (...)

Niestety nie mogę opublikować bardziej uzasadnionego wyjaśnienia ze szczegółami z mojej własnej bashkonfiguracji, ponieważ jestem zshfacetem ...

mpy
źródło
2
Jawne ustawienie opcji historii w moim ~/.bash_profilerozwiązało problem. Używam teraz ~/.bash_historyjako pliku historii, ale po prostu dodałem wszystkie wiersze z ~/.bashrcpokazanego w moim pytaniu do ~/.bash_profile. Nadal nie jestem pewien, kto spieprzył interaktywne muszle, ale wydaje się, że teraz działa, dzięki!
terdon
1
Przepraszam, że nie zaakceptowałem, ale zapomniałem opublikować odpowiedź wyjaśniającą, co się dzieje. Dowiedziałem się tego z pomocą @Gilles jakiś czas temu i w końcu zacząłem pisać odpowiedź. Chciałem zaakceptować mój, ponieważ tak naprawdę wyjaśnia problem, zamiast oferować (bardzo dobre) obejście i może pomóc przyszłym użytkownikom.
terdon
2

Ponieważ wszystkie ustawienia są uporządkowane według strony podręcznika i ponieważ plik historii nie jest ograniczony rozmiarem (bajtami), jedyne możliwe wyjaśnienie, jakie mogę wymyślić. Ma to związek z tym, jak umiera skorupa.

Zgodnie z odniesieniem online wdzięczne wyjście (zapisana historia) następuje tylko wtedy, gdy powłoka otrzymuje SIGHUP. Naprawdę nie potrafię wyjaśnić, w jaki sposób twój system propaguje sygnały po ponownym uruchomieniu, ale podejrzewam, że twoja powłoka kończy pracę z SIGKILL lub SIGPWR.

Może to być spowodowane tym, że WM działa asynchronicznie (poczekaj), a emulator terminala odrodził się z WM, gdzie bash otrzymuje sygnał wymuszający wyjście inny niż SIGHUP. Może się również zdarzyć, że system operacyjny szybko wyśle ​​„ostateczne zabójstwo” do wszystkich procesów, zanim początkowy wdzięczny SIGHUP zdoła dostać się do powłoki przez X -> WM -> xterm, być może dlatego, że X lub WM trwa dłużej niż wyjście niż system operacyjny musi być gotowy do upadku.

Jestem na głębokich wodach z tymi rzeczami, ale myślę, że coś w tym stylu powoduje nieprawidłowe zachowanie. Miałem już ten problem, a najbardziej solidnym lekarstwem jest exitbash, w którym chcesz zachować historię.

Zauważyłem history -aw twoim pytaniu i nie mogę wymyślić, dlaczego to nie wystarczyłoby, aby zachować historię.

Możesz rozwiązać problem, zastanawiając się, co tak naprawdę zabija twój bash, i przechodząc do ustalenia źródła sygnału i naprawiając problem, lub po prostu opróżnij historię, gdy wiesz, który sygnał jest ostatni (zakładając, że dyski są nadal online ):

trap "echo got 1  >/tmp/sig1;  exit" SIGHUP
trap "echo got 2  >/tmp/sig2;  exit" SIGINT
trap "echo got 15 >/tmp/sig15; exit" SIGTERM
 .. and so on...

Załączony zrzut ekranu ilustruje to, o czym mówię w akapitach drugim i trzecim. Sekwencja, w której ja strzelam z lewej , zabij lewą z prawej i przeglądaj historię.

uderzenie człowieka

Podczas uruchamiania (...) Plik o nazwie HISTFILE jest w razie potrzeby obcinany, aby zawierał nie więcej niż liczbę wierszy określoną przez wartość HISTFILESIZE (+ domyślnie 500).

Jeśli włączona jest opcja powłoki histappend (+ domyślnie tutaj), linie są dołączane do pliku historii, w przeciwnym razie plik historii zostanie nadpisany.

referencje online

3.7.6 Sygnały

Gdy Bash jest interaktywny, przy braku pułapek, ignoruje SIGTERM (tak, że „kill 0” nie zabija interaktywnej powłoki), a SIGINT jest przechwytywany i obsługiwany (tak, że wbudowane oczekiwanie jest przerywane). Gdy Bash otrzymuje SIGINT, wyrywa się z wykonanych pętli. We wszystkich przypadkach Bash ignoruje SIGQUIT. Jeśli kontrola zadań jest aktywna (patrz Kontrola zadań), Bash ignoruje SIGTTIN, SIGTTOU i SIGTSTP.

Wbudowane polecenia uruchamiane przez Bash mają procedury obsługi sygnałów ustawione na wartości odziedziczone przez powłokę od jej rodzica. Gdy kontrola zadań nie działa, asynchroniczne polecenia ignorują SIGINT i SIGQUIT oprócz tych odziedziczonych programów obsługi. Polecenia uruchamiane w wyniku podstawienia poleceń ignorują generowane z klawiatury sygnały kontrolne zadań SIGTTIN, SIGTTOU i SIGTSTP.

Powłoka wychodzi domyślnie po otrzymaniu SIGHUP. Przed wyjściem interaktywna powłoka ponownie wysyła SIGHUP do wszystkich zadań, uruchomionych lub zatrzymanych. Zatrzymane zadania są wysyłane SIGCONT, aby upewnić się, że otrzymają SIGHUP. Aby zapobiec wysyłaniu przez powłokę sygnału SIGHUP do określonego zadania, należy go usunąć z tabeli zadań z wbudowanym disown (patrz Wbudowane funkcje kontroli zadań) lub zaznaczyć, że nie może odbierać SIGHUP przy użyciu disown -h.

Jeśli opcja powłoki huponexit została ustawiona w shopt (patrz Wbudowane Shopt), Bash wysyła SIGHUP do wszystkich zadań, gdy kończy się interaktywna powłoka logowania.

Jeśli Bash czeka na zakończenie komendy i odbiera sygnał, dla którego ustawiono pułapkę, pułapka nie zostanie wykonana, dopóki polecenie się nie zakończy. Gdy Bash czeka na polecenie asynchroniczne poprzez wbudowane oczekiwanie, odbiór sygnału, dla którego ustawiono pułapkę, spowoduje natychmiastowe zwrócenie wbudowanego oczekiwania ze statusem wyjścia większym niż 128, natychmiast po którym pułapka zostanie wykonana.

przykładowy zrzut ekranu

sygnały

Ярослав Рахматуллин
źródło
Tak naprawdę nie rozumiem, co robisz na tym zrzucie ekranu. Co /tmp/psozabijasz? Rozumiem twój punkt widzenia na temat różnych sygnałów zabicia (choć, jak mówisz, myślałem, że właśnie o history -ato chodzi). Przetestuję to przez chwilę i zdam relację.
terdon
$ cat tmp / ps * \ n ps -o pid = | head -n1> ~ / tmp / pso \ n 17201 \ n
Ярослав Рахматуллин
0

Sprawdź / etc / profile i /etc/profile.d/*

Może jest tam coś nie tak z ustawieniami historii.

Mabagu
źródło
Dzięki, ale grep -r HIST /etc/profile.d/nic nie zwraca, a ja już sprawdziłem /etc/profile.
terdon