15%

Zaoszczędź 15% na wszystkich usługach hostingowych

Sprawdź swoje umiejętności i zdobądź Rabat na dowolny plan hostingowy

Użyj kodu:

Skills
Rozpocznij
09.10.2024

Polecenie `history` w Linux: Kompletny przewodnik po historii Bash

Polecenie `history` w Linux to wbudowane narzędzie powłoki Bash, które rejestruje, wyświetla i zarządza każdym poleceniem wykonanym w sesji terminala. Odczytuje i zapisuje dane do `~/.bash_history`, pliku tekstowego w katalogu domowym każdego użytkownika, umożliwiając przywoływanie, wyszukiwanie, ponowne wykonywanie i audytowanie poleceń między sesjami bez konieczności ich ponownego wpisywania.

Dla administratorów systemów i zaawansowanych użytkowników historia Bash to nie tylko wygodna funkcja — jest to operacyjny ślad audytu, narzędzie do debugowania i mnożnik produktywności. Zrozumienie jej wewnętrznego działania, zmiennych konfiguracyjnych i implikacji bezpieczeństwa odróżnia zwykłych użytkowników od inżynierów, którzy wydobywają maksymalną wartość z wiersza poleceń.

Jak działa historia Bash wewnętrznie

Po otwarciu sesji terminala Bash ładuje zawartość `~/.bash_history` do listy przechowywanej w pamięci. Podczas wykonywania poleceń są one dołączane do tego bufora w pamięci. Gdy sesja kończy się normalnie (przez `exit` lub `logout`), bufor jest zapisywany z powrotem do `~/.bash_history` zgodnie z regułami zdefiniowanymi przez zmienne środowiskowe.

Ta architektura ma krytyczną implikację: jeśli sesja zakończy się nieprawidłowo (utrata zasilania, rozłączenie SSH, `kill -9`), polecenia z tej sesji mogą nigdy nie zostać zapisane na dysku. Jest to częste źródło nieporozumień, gdy administratorzy tracą ślad poleceń wykonanych podczas przerwanej sesji.

Dwie opcje powłoki modyfikują domyślne zachowanie zapisu przy wyjściu:

  • `shopt -s histappend` — dołącza nową historię do `~/.bash_history` zamiast ją nadpisywać. Jest to niezbędne w środowiskach wielosesyjnych.
  • `PROMPT_COMMAND='history -a'` — wymusza dołączenie przez Bash najnowszego polecenia do pliku historii po każdym znaku zachęty, umożliwiając trwałość w czasie rzeczywistym i widoczność między terminalami.

Bez `histappend` wygrywa ostatnia zamknięta powłoka — nadpisuje plik historii, po cichu odrzucając wpisy ze wszystkich innych równoczesnych sesji.

Podstawowe użycie polecenia `history`

Wyświetlanie pełnej historii poleceń

“`bash

history

“`

Wyświetla numerowaną listę przechowywanych poleceń. Numer po lewej stronie to indeks historii, używany do oznaczników zdarzeń.

Wyświetlanie określonej liczby ostatnich poleceń

“`bash

history 20

“`

Pokazuje ostatnie 20 poleceń. Przydatne, gdy potrzebujesz szybkiego podglądu ostatniej aktywności bez przewijania setek wpisów.

Natychmiastowy zapis historii bieżącej sesji do pliku

“`bash

history -w

“`

Wymusza natychmiastowy zapis bufora historii z pamięci do `~/.bash_history`. Użyj tego przed zamknięciem krytycznej sesji, aby upewnić się, że nic nie zostanie utracone.

Odczyt historii z pliku do bieżącej sesji

“`bash

history -r

“`

Ponownie ładuje `~/.bash_history` do pamięci bieżącej sesji. Przydatne, gdy chcesz uzyskać dostęp do poleceń wpisanych w innym oknie terminala podczas tej samej sesji logowania.

Przywoływanie i ponowne wykonywanie poleceń

Oznaczniki zdarzeń z `!`

Składnia oznaczników zdarzeń w Bash umożliwia bezpośrednie ponowne wykonywanie historycznych poleceń przez odwołanie:

OznacznikZachowanie
`!!`Ponownie uruchamia bezpośrednio poprzednie polecenie
`!n`Uruchamia polecenie o indeksie historii `n`
`!-n`Uruchamia polecenie `n` pozycji wstecz od bieżącego
`!string`Uruchamia najnowsze polecenie zaczynające się od `string`
`!?string?`Uruchamia najnowsze polecenie zawierające `string` gdziekolwiek
`!$`Podstawia ostatni argument poprzedniego polecenia
`!*`Podstawia wszystkie argumenty poprzedniego polecenia

Praktyczny przykład — ponowne użycie ostatniego argumentu:

“`bash

mkdir /var/www/myproject

cd !$

“`

`!$` rozszerza się do `/var/www/myproject`, oszczędzając ponownego wpisywania ścieżki. Jest to jedna z najbardziej niedocenianych, a zarazem najbardziej wartościowych funkcji historii Bash.

Podgląd przed wykonaniem:

Dołącz `:p` do dowolnego oznacznika zdarzenia, aby wydrukować polecenie bez jego uruchamiania:

“`bash

!42:p

“`

Jest to krytyczny nawyk bezpieczeństwa podczas pracy na serwerach produkcyjnych. Zawsze przeglądaj destrukcyjne polecenia przed wykonaniem.

Oznaczniki słów do wyodrębniania argumentów

Poza ponownym uruchamianiem całych poleceń, Bash pozwala wyodrębniać konkretne argumenty z wpisów historii:

“`bash

!!:2 # Second word (argument) of the last command

!!:1-3 # Words 1 through 3 of the last command

!ssh:$ # Last argument of the most recent ssh command

“`

Ten poziom szczegółowości jest nieoceniony przy konstruowaniu złożonych potoków lub powtarzaniu operacji na tych samych ścieżkach plików.

Skróty klawiaturowe do nawigacji po historii

SkrótAkcja
`Up Arrow` / `Ctrl+P`Przejście do poprzedniego polecenia
`Down Arrow` / `Ctrl+N`Przejście do następnego polecenia
`Ctrl+R`Przyrostowe wyszukiwanie wsteczne w historii
`Ctrl+S`Przyrostowe wyszukiwanie do przodu (wymaga `stty -ixon`)
`Alt+.`Wstawia ostatni argument poprzedniego polecenia
`Ctrl+G`Anuluje bieżące wyszukiwanie w historii

Uwaga dotycząca `Ctrl+S`: Domyślnie `Ctrl+S` wyzwala sterowanie przepływem XON/XOFF i zawiesza terminal. Aby włączyć wyszukiwanie historii do przodu, dodaj `stty -ixon` do swojego `~/.bashrc`.

Wyszukiwanie wsteczne z `Ctrl+R`

“`

(reverse-i-search)`git': git commit -am "fix: resolve race condition"

“`

Wpisz podciąg, a Bash przyrostowo dopasuje najnowsze polecenie go zawierające. Naciśnij `Ctrl+R` ponownie, aby przejść do starszych dopasowań. Naciśnij `Enter`, aby wykonać, lub `Ctrl+G`, aby przerwać bez uruchamiania czegokolwiek.

W przypadku wyszukiwań w historii o dużej objętości, przekieruj przez `grep`:

“`bash

history | grep "docker run"

history | grep -E "^[[:space:]]+[0-9]+[[:space:]]+ssh"

“`

Edytowanie i zarządzanie wpisami historii

Usuwanie konkretnego wpisu

“`bash

history -d 87

“`

Usuwa polecenie o indeksie 87 z listy w pamięci. Aby uczynić to trwałym, użyj następnie `history -w`, aby zapisać zmodyfikowaną listę z powrotem na dysk.

Usuwanie zakresu wpisów

“`bash

for i in $(seq 85 90); do history -d 85; done

“`

Ponieważ usuwanie przesuwa indeksy, zawsze usuwaj ten sam numer indeksu w pętli zamiast go inkrementować.

Czyszczenie całej historii w pamięci

“`bash

history -c

“`

Czyści bufor historii bieżącej sesji. Nie dotyka `~/.bash_history` na dysku.

Całkowite usunięcie całej historii

“`bash

history -c && history -w

“`

Czyści bufor w pamięci, a następnie zapisuje pusty bufor do `~/.bash_history`, skutecznie obcinając plik. Jest to prawidłowa dwuetapowa sekwencja — użycie samego `> ~/.bash_history` nie czyści bufora w pamięci, więc plik może zostać ponownie zapełniony przy wyjściu z sesji.

Konfigurowanie historii Bash: zmienne środowiskowe

Całe zachowanie historii jest regulowane przez zmienne środowiskowe, zazwyczaj ustawiane w `~/.bashrc` (interaktywne powłoki bez logowania) lub `~/.bash_profile` / `~/.profile` (powłoki logowania). Zmiany wchodzą w życie po załadowaniu pliku:

“`bash

source ~/.bashrc

“`

`HISTSIZE`

Kontroluje liczbę poleceń przechowywanych w pamięci podczas aktywnej sesji.

“`bash

export HISTSIZE=10000

“`

Ustawienie tego na `0` całkowicie wyłącza historię w pamięci. Ustawienie na `-1` (w Bash 4.3+) sprawia, że jest nieograniczona.

`HISTFILESIZE`

Kontroluje maksymalną liczbę linii przechowywanych w `~/.bash_history` na dysku.

“`bash

export HISTFILESIZE=20000

“`

Gdy plik przekroczy ten limit, Bash usuwa najstarsze wpisy. W środowiskach wymagających zgodności z przepisami ustaw tę wartość na dużą liczbę i połącz z rotacją logów.

`HISTCONTROL`

Określa reguły filtrowania dotyczące tego, które polecenia są rejestrowane.

WartośćZachowanie
`ignoredups`Pomija kolejne zduplikowane polecenia
`ignorespace`Pomija polecenia poprzedzone spacją
`ignoreboth`Łączy oba powyższe
`erasedups`Usuwa wszystkie poprzednie wystąpienia polecenia przed dodaniem nowego

“`bash

export HISTCONTROL=ignoreboth

“`

Przypadek użycia bezpieczeństwa dla `ignorespace`: Poprzedź dowolne polecenie zawierające hasło lub sekret spacją, aby zapobiec jego zapisaniu:

“`bash

mysql -u root -pSuperSecretPassword

“`

Jest to powszechnie stosowana praktyka bezpieczeństwa operacyjnego na współdzielonych lub wieloużytkownikowych systemach.

`HISTTIMEFORMAT`

Dodaje znacznik czasu do każdego wpisu historii, przechowywany jako linia komentarza w `~/.bash_history`.

“`bash

export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "

“`

Przykład wyjścia:

“`

487 2024-11-14 09:32:17 systemctl restart nginx

488 2024-11-14 09:32:45 tail -f /var/log/nginx/error.log

“`

Znaczniki czasu są niezbędne do kryminalistyki po incydentach w środowiskach Hostingu VPS i dedykowanej infrastrukturze. Bez nich wiesz *co* zostało uruchomione, ale nie *kiedy*.

`HISTIGNORE`

Rozdzielona dwukropkami lista wzorców glob. Polecenia pasujące do dowolnego wzorca nie są zapisywane w historii.

“`bash

export HISTIGNORE="ls:ll:la:cd:pwd:exit:clear:history"

“`

Zapobiega to zaśmiecaniu historii trywialnymi poleceniami i rozmywaniu wyników wyszukiwania. Możesz również używać symboli wieloznacznych:

“`bash

export HISTIGNORE="*password*:*secret*:*token*"

“`

Jest to środek ochrony w głąb — połącz go z `ignorespace` dla maksymalnej higieny poświadczeń.

Zmienne konfiguracyjne historii Bash: pełna tabela referencyjna

ZmiennaDomyślnaPrzeznaczenie
`HISTSIZE`500–1000Polecenia przechowywane w pamięci na sesję
`HISTFILESIZE`500–2000Linie przechowywane w `~/.bash_history`
`HISTCONTROL`(nieustawiona)Reguły filtrowania dla rejestrowanych poleceń
`HISTTIMEFORMAT`(nieustawiona)Format znacznika czasu poprzedzający wpisy
`HISTIGNORE`(nieustawiona)Wzorce glob dla poleceń do wykluczenia
`HISTFILE``~/.bash_history`Ścieżka do pliku historii
`histappend` (shopt)wyłączonaDołączanie vs. nadpisywanie przy wyjściu z sesji

Współdzielenie historii między wieloma sesjami terminala

Domyślnie każda sesja Bash utrzymuje własny izolowany bufor historii. Polecenia wpisane w Terminalu A są niewidoczne dla Terminala B, dopóki obie sesje nie zostaną zamknięte i plik nie zostanie zapisany. Dla administratorów zarządzających wieloma sesjami SSH jednocześnie na Serwerach Dedykowanych tworzy to luki w rejestrze operacyjnym.

Zalecana konfiguracja do współdzielenia historii między sesjami w czasie rzeczywistym:

“`bash

~/.bashrc

export HISTSIZE=100000

export HISTFILESIZE=100000

export HISTCONTROL=ignoreboth

export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "

shopt -s histappend

PROMPT_COMMAND='history -a; history -c; history -r'

“`

Co to robi:

  • `history -a` — dołącza najnowsze polecenie do pliku
  • `history -c` — czyści bufor w pamięci
  • `history -r` — ponownie ładuje plik do pamięci

Po każdym poleceniu każda sesja terminala widzi kompletną, ujednoliconą historię ze wszystkich aktywnych sesji. Kompromisem jest niewielkie obciążenie przy wykonywaniu `PROMPT_COMMAND`, które w praktyce jest pomijalnie małe.

Efektywne wyszukiwanie w historii: zaawansowane techniki

`fzf` — rozmyte wyszukiwanie w historii

Narzędzie `fzf` przekształca wyszukiwanie w historii z liniowego skanowania w interaktywny interfejs rozmytego dopasowywania:

“`bash

Install fzf (Debian/Ubuntu)

sudo apt install fzf

Bind Ctrl+R to fzf-powered history search

Add to ~/.bashrc:

[ -f ~/.fzf.bash ] && source ~/.fzf.bash

“`

Po skonfigurowaniu `Ctrl+R` otwiera pełnoekranowe rozmyte wyszukiwanie w całej historii. Jest to szczególnie przydatne przy dużych plikach historii (ponad 10 000 wpisów), gdzie `grep` staje się uciążliwe.

Wyodrębnianie historii do skryptów

“`bash

Export all unique commands containing "iptables" to a script

history | grep iptables | awk '{$1=""; print $0}' | sort -u > iptables_audit.sh

“`

Ten wzorzec jest przydatny do rekonstruowania instrukcji obsługi z poleceń ad-hoc wykonanych podczas reagowania na incydenty.

Kwestie bezpieczeństwa dotyczące historii Bash

Historia Bash to narzędzie obosieczne. Przyspiesza legalne przepływy pracy, ale stanowi również znaczącą powierzchnię ataku.

Kluczowe zagrożenia i środki zaradcze:

  • Ujawnienie poświadczeń: Hasła przekazywane jako argumenty wiersza poleceń (np. `curl -u admin:password`) są przechowywane w postaci zwykłego tekstu w `~/.bash_history`. Zamiast tego używaj `ignorespace`, `HISTIGNORE` lub zmiennych środowiskowych.
  • Kryminalistyka eskalacji uprawnień: Atakujący, którzy uzyskują dostęp do powłoki, rutynowo odczytują `~/.bash_history`, aby zrozumieć środowisko, odkryć poświadczenia i zidentyfikować wartościowe cele. Ustaw restrykcyjne uprawnienia: `chmod 600 ~/.bash_history`.
  • Manipulowanie historią: Skompromitowany użytkownik może uruchomić `history -c && history -w`, aby usunąć wszelkie ślady. Do celów audytu w systemach produkcyjnych rozważ rejestrowanie poleceń oparte na `auditd` lub `syslog`, którym użytkownik nie może manipulować.
  • Izolacja historii roota: Historia użytkownika root jest przechowywana w `/root/.bash_history`. Upewnij się, że ten plik nie jest dostępny do odczytu dla wszystkich i jest uwzględniony w zakresie kopii zapasowych i audytu.

W środowiskach wymagających ścisłego audytu poleceń — takich jak infrastruktura zgodna z PCI-DSS lub SOC 2 — sama historia Bash jest niewystarczająca. Połącz ją z audytem na poziomie jądra przez `auditd` i centralnym przesyłaniem logów.

Historia Bash a alternatywne systemy historii powłoki

FunkcjaHistoria BashHistoria ZshHistoria Fish
Domyślny plik historii`~/.bash_history``~/.zsh_history``~/.local/share/fish/fish_history`
Obsługa znaczników czasuPrzez `HISTTIMEFORMAT`WbudowanaWbudowana (format YAML)
Obsługa duplikatów`HISTCONTROL`Opcja `HIST_IGNORE_DUPS`Automatyczna deduplikacja
Współdzielenie między sesjamiRęczne (`PROMPT_COMMAND`)Opcja `INC_APPEND_HISTORY`Automatyczne (współdzielone domyślnie)
Interfejs wyszukiwania`Ctrl+R` (liniowe)`Ctrl+R` (liniowe)Podświetlanie składni, kontekstowe
Maksymalny rozmiar historiiZmienna `HISTFILESIZE`Zmienna `SAVEHIST`Brak twardego limitu
Mechanizm blokowaniaBrak (możliwe wyścigi)Obsługiwane blokowanie plikówOparte na SQLite (atomowe zapisy)

Głównym ograniczeniem historii Bash jest brak wbudowanego blokowania, co może powodować wyścigi, gdy wiele sesji zapisuje jednocześnie. Zsh i Fish obsługują to bardziej elegancko na poziomie powłoki.

Praktyczna konfiguracja dla środowisk produkcyjnych

Poniżej znajduje się sprawdzona konfiguracja historii `~/.bashrc` odpowiednia dla produkcyjnych serwerów Linux, w tym tych z VPS z cPanel lub niestandardowymi panelami sterowania:

“`bash

— Bash History Configuration —

export HISTSIZE=50000

export HISTFILESIZE=50000

export HISTCONTROL=ignoreboth:erasedups

export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "

export HISTIGNORE="ls:ll:la:cd:pwd:exit:clear:bg:fg:jobs"

export HISTFILE=~/.bash_history

Append to history file; don't overwrite

shopt -s histappend

Save and reload history after each command

PROMPT_COMMAND='history -a; history -c; history -r'

Enable multi-line command history as single entry

shopt -s cmdhist

Store multi-line commands with embedded newlines

shopt -s lithist

“`

`cmdhist` i `lithist` zasługują na szczególną uwagę. Bez `cmdhist` wieloliniowe polecenie (jak pętla `for` wpisana interaktywnie) jest przechowywane jako oddzielne linie, co uniemożliwia jego czyste ponowne wykonanie. Gdy `cmdhist` jest włączone i `lithist` jest ustawione, cała konstrukcja jest przechowywana jako pojedynczy wpis historii z dosłownymi znakami nowej linii, zachowując jej strukturę.

Automatyzacja przepływów pracy opartych na historii

Generowanie raportu częstotliwości poleceń

“`bash

history | awk '{print $2}' | sort | uniq -c | sort -rn | head -20

“`

Ujawnia to 20 najczęściej używanych poleceń — przydatne do identyfikowania kandydatów na aliasy lub funkcje powłoki.

Audyt użycia `sudo`

“`bash

history | grep sudo | awk '{$1=""; print $0}'

“`

W środowiskach Paneli Sterowania VPS zapewnia to szybki audyt uprzywilejowanych operacji wykonanych podczas sesji.

Rekonstrukcja osi czasu sesji

“`bash

HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S " history | grep "2024-11-14"

“`

Filtruje wszystkie polecenia wykonane w określonym dniu — nieocenione podczas przeglądów po incydentach.

Kluczowe wnioski techniczne i lista kontrolna decyzji

Przed wdrożeniem konfiguracji historii Bash w dowolnym środowisku zweryfikuj następujące kwestie:

  • `shopt -s histappend` jest ustawione — zapobiega utracie historii spowodowanej nadpisywaniem się przez równoczesne sesje
  • `HISTSIZE` i `HISTFILESIZE` są oba skonfigurowane — ustawienie tylko jednego pozostawia drugie z domyślną wartością, powodując nieoczekiwane obcinanie
  • `HISTTIMEFORMAT` jest włączone — bez znaczników czasu historia nie ma wartości kryminalistycznej
  • `HISTCONTROL=ignoreboth` jest ustawione co najmniej — redukuje szum i zapobiega rejestrowaniu poleceń sąsiadujących z poświadczeniami
  • `HISTIGNORE` wyklucza trywialne polecenia — utrzymuje wysoki stosunek sygnału do szumu w historii
  • `~/.bash_history` ma `chmod 600` — uniemożliwia innym użytkownikom odczytanie historii poleceń
  • `cmdhist` jest włączone — zapewnia przechowywanie wieloliniowych poleceń jako spójnych jednostek
  • `PROMPT_COMMAND` synchronizuje historię w czasie rzeczywistym — wymagane w środowiskach wielosesyjnych
  • `auditd` jest wdrożone równolegle — dla systemów produkcyjnych, gdzie wymagane jest rejestrowanie odporne na manipulacje
  • Poświadczenia nigdy nie są przekazywane jako argumenty CLI — zamiast tego używaj zmiennych środowiskowych, `.netrc` lub menedżerów sekretów

Często zadawane pytania

Dlaczego moja historia Bash znika po zamknięciu sesji SSH?

Dzieje się tak zazwyczaj dlatego, że `shopt -s histappend` nie jest ustawione. Bez tego każda sesja nadpisuje `~/.bash_history` przy wyjściu. Jeśli sesja kończy się nieprawidłowo (utrata połączenia sieciowego, `kill -9`), zapis w ogóle nie następuje. Ustaw `histappend` i `PROMPT_COMMAND='history -a'`, aby utrwalać polecenia w czasie rzeczywistym.

Jak zapobiec zapisywaniu haseł w historii Bash?

Użyj dwóch uzupełniających się technik: poprzedź polecenie spacją (wymaga `HISTCONTROL=ignorespace` lub `ignoreboth`) i dodaj wrażliwe wzorce poleceń do `HISTIGNORE`. Dla długoterminowej higieny nigdy nie przekazuj sekretów jako argumentów CLI — używaj zmiennych środowiskowych lub dedykowanych narzędzi do zarządzania sekretami.

Jaka jest różnica między `HISTSIZE` a `HISTFILESIZE`?

`HISTSIZE` kontroluje liczbę poleceń, które Bash przechowuje w pamięci podczas aktywnej sesji. `HISTFILESIZE` kontroluje liczbę linii zachowywanych w `~/.bash_history` na dysku. Oba muszą być ustawione jawnie — duże `HISTSIZE` z małym `HISTFILESIZE` oznacza, że historia w sesji jest bogata, ale większość z niej jest odrzucana po zakończeniu sesji.

Czy usunięte wpisy historii można odzyskać?

Po wykonaniu `history -c && history -w` bufor w pamięci jest czyszczony, a plik obcinany — standardowe odzyskiwanie nie jest możliwe. Jednak jeśli system używa migawek systemu plików lub rozwiązań do tworzenia kopii zapasowych, poprzednia wersja `~/.bash_history` może być możliwa do odzyskania z migawki. To kolejny powód, aby wdrożyć `auditd` do rejestrowania odpornego na manipulacje w krytycznej infrastrukturze.

Jak współdzielić historię Bash między wieloma równoczesnymi sesjami terminala?

Dodaj następujące elementy do `~/.bashrc`: `shopt -s histappend` i `PROMPT_COMMAND='history -a; history -c; history -r'`. Wymusza to dołączanie przez każdą sesję najnowszego polecenia do współdzielonego pliku i ponowne ładowanie pełnego pliku po każdym znaku zachęty, dając wszystkim aktywnym terminalom ujednolicony widok historii poleceń w czasie rzeczywistym.

15%

Zaoszczędź 15% na wszystkich usługach hostingowych

Sprawdź swoje umiejętności i zdobądź Rabat na dowolny plan hostingowy

Użyj kodu:

Skills
Rozpocznij