Dziwne zachowanie historii bash podczas uruchamiania wielu sesji

15

Jak przechowywana jest historia wiersza poleceń, gdy korzystam z wielu okien terminali? Wiem, że jest przechowywany, .bash_historyale nie widzę logiki, która historia jest używana, jeśli otworzę nowe okno. Prawie wydaje się niedeterministyczny w tym sensie, że nigdy nie wiem, jakie polecenie zobaczę, jeśli spróbuję użyć strzałki w górę w nowym oknie.

Czy ktoś może to wyjaśnić?

Czy istnieje sposób kontrolowania historii w taki sposób, że mogę ponownie wykorzystać historię z określonego okna?

Alex Gitelman
źródło

Odpowiedzi:

14

Aby zrozumieć zachowanie historii bash, najpierw musisz wiedzieć:

  1. W pliku historii znajduje się historia.
  2. W pamięci procesu bash znajduje się historia.
  3. Historia w pamięci jednego procesu bash nie jest zsynchronizowana z historią w pamięci innego procesu bash.
  4. Historia w pamięci procesu bash nie jest zsynchronizowana z historią w pliku, chyba że zostanie wyraźnie poproszony o określone zdarzenie lub podczas niego (patrz poniżej).

Przy użyciu ustawień domyślnych cykl życia sesji bash w odniesieniu do historii wygląda następująco:

  1. Podczas uruchamiania bash odczyta plik historii. Zawartość pliku historii znajduje się teraz w pamięci procesu bash.
  2. Podczas normalnego użytkowania manipulowana jest tylko historia w pamięci.
  3. Podczas zamykania historia w pamięci jest zapisywana do pliku historii, zastępując wcześniejszą zawartość pliku historii.

Pozornie niedeterministyczne zachowanie, które zaobserwowałeś, jest głównie spowodowane tym, że zawartość pliku historii jest zawsze historią ostatniej zamkniętej sesji bash, a bash czyta plik historii tylko podczas uruchamiania.

Przeczytaj instrukcję bash, aby uzyskać bardziej szczegółowe wyjaśnienie procesu uruchamiania i zamykania.

Zauważ, że przy ustawieniach domyślnych mam na myśli ustawienia domyślne z bash. Twoja dystrybucja mogła dostarczyć .bashrc(lub /etc/bash.bashrc), które zmieniają to zachowanie.

Włączając opcję powłoki histappend, możesz nakazać bashowi dołączenie zamiast zastępowania pliku historii. Możesz włączyć histappendza pomocą polecenia shopt -s histappend. Aby ta opcja była zawsze włączona, musisz umieścić polecenie w swoim .bashrc(lub innym pliku inicjującym). Przeczytaj więcej o shoptpoleceniu w podręczniku bash

Zauważ, że włączenie histappendnie zmniejszy znacznie pozornie niedeterministycznego zachowania. Dzieje się tak, ponieważ każda sesja bash wciąż ma swoją własną historię w pamięci. Możliwe jest posiadanie głównie zsynchronizowanej historii bash. Istnieje przewodnik, jak sprawić, by każdy proces bash miał zsynchronizowaną historię w wątku dotyczącym przepełnienia stosu .

za pomocą wbudowanego polecenia historymożesz jawnie nakazać bashowi odczytanie historii z pliku do pamięci lub zapisanie z pamięci do pliku. Na przykład: history -rodczytuje zawartość pliku i dołącza go do historii w pamięci. history -wzapisze bieżącą historię z pamięci do pliku, zastępując poprzednią zawartość. Zasadniczo dzieje się to podczas wyłączania. Przeczytaj więcej o historypoleceniu w podręczniku bash

Dla kompletności oto lista wewnętrznych zmiennych, które modyfikują zachowanie historii:

  • HISTFILE: plik do odczytu i zapisu historii.
  • HISTFILESIZE: maksymalna liczba wierszy dla pliku historii.
  • HISTSIZE: maksymalna liczba wierszy dla historii w pamięci.
  • HISTCONTROL, HISTIGNORE, HISTTIMEFORMAT: Nie odnosi się do tej dyskusji. Przeczytać instrukcję bash szczegóły.
lesmana
źródło
Dobre wytłumaczenie. Wspomniałeś o zamknięciu, ale co z zabiciem sesji terminalowej? Sesję można zabić przez wylogowanie lub interfejs użytkownika lub za pomocą innych środków, takich jak zerwanie połączenia sieciowego. Jeśli cały plik historii zostanie zastąpiony i masz wiele sesji, czy mówisz, że historia z ostatniej zamkniętej zostanie użyta w pliku historii? To może tłumaczyć zachowanie niedeterministyczne.
Alex Gitelman,
punkt cyklu życia (3) jest nieprawidłowy. Wygląda na to, że tylko pierwsza sesja bash zapisze się w pliku historii. Test: Otwórz 2 sesje w kolejności - a, b. Wykonaj „echo hello” w b . Następnie wyjdź b . Następnie otwórz nową sesję c . Ta sesja nie będzie miała echa w historii.
user606723,
@AlexGitelman: jeśli proces bash zostanie zabity, nie będzie szansy na zastąpienie pliku historii. i tak, historia z ostatniej zamkniętej sesji to ta, która będzie w pliku historii.
lesmana,
@ user606723: punkt 3 jest poprawny. przeczytaj instrukcję bash. eksperymentuj ponownie, używając minimalnego .bashrcpliku. zwróć uwagę, że Twoja dystrybucja mogła zmienić niektóre ustawienia w /etc/bash.bashrc. sprawdź specjalnie dla opcji powłoki histappend.
lesmana,
0

AFAIK, polecenia bash są zapisywane po zakończeniu sesji SSH. Tak więc polecenia nie są zapisywane, gdy sesja kończy się nienormalnie (na przykład z powodu awarii sieci). Mówię tutaj o sesjach SSH. Lokalne terminale mogą stosować podobne podejście.

Podczas otwierania wielu sesji w tym samym czasie polecenia wpisane w jednej sesji nie są widoczne w drugiej, gdy obie są aktywne. Jednak po zakończeniu sesji zobaczysz te polecenia, ponownie je otwórz.

Khaled
źródło
Nie takiego zachowania się doświadczyłem. Mogę to potwierdzić, wykonując szybki test, w którym otwieram sesję ssh, wykonuję polecenie i wykonuję pełne wdzięku wyjście. W tym przypadku miałem inną wcześniej aktywną sesję ssh. W tej wcześniej istniejącej sesji bash sprawdzam .bash_history i nie znajduję nic nagranego. Wydaje mi się prawdopodobne, że pierwsza uruchomiona sesja bash jest jedyną, która kończy nagrywanie do .bash_history.
user606723,
Zakończenie sesji nie wpłynie na aktualnie uruchomione sesje, ale wpłynie na nowe sesje!
Khaled
Co jeśli nie jest to SSH, ale okno terminala Gnome, które zamykam za pomocą interfejsu użytkownika?
Alex Gitelman,
To musi zostać zweryfikowane. Obecnie nie mam dostępu do terminala Gnome!
Khaled
@Khaled, przetestowałem to, nie wpływa na nowe sesje. (W każdym razie sprawdzałem .bash_history, czyli tam, gdzie bash pobiera historię poleceń dla nowych sesji, więc wiedziałem, że to nie zadziała, ale i tak cię upokorzyłem.)
user606723