Zachowaj historię bash w wielu oknach terminala

526

Konsekwentnie mam więcej niż jeden otwarty terminal. Gdziekolwiek od dwóch do dziesięciu, robiąc różne bity i boby. Powiedzmy teraz, że uruchamiam ponownie i otwieram inny zestaw terminali. Niektórzy pamiętają pewne rzeczy, inni zapominają.

Chcę historii, która:

  • Zapamiętuje wszystko z każdego terminala
  • Jest natychmiast dostępny z każdego terminala (np. Jeśli jestem lsw jednym, przełącz się na inny już działający terminal, a następnie naciśnij przycisk w górę, lspokazuje się)
  • Nie zapomina polecenia, jeśli z przodu polecenia są spacje.

Co mogę zrobić, aby bash działał w ten sposób?

Oli
źródło
57
Widzę zaletę tego, ale osobiście NIENAWIDZĘ tego w mojej skorupie. Zwykle trzymam otwarte 3 lub 4 karty w moim terminalu do bardzo specyficznych zastosowań: jedna do uruchamiania „make”, jedna z vi, jedna do uruchamiania rzeczy itp. Więc kiedy kompiluję, przechodzę do karty 1, uderzam w górę i „make” pojawia się i tak dalej. Jest to dla mnie niezwykle produktywne. Więc jeśli nagle przejdę do zakładki „make” i uderzę i pojawi się jakieś losowe polecenie grep, naprawdę się wkurzę! Ale tylko osobista notatka
axel_c
4
@ax__c to prawda. Nie mogę wymyślić inteligentnego sposobu, aby to zrobić, gdy istniejące terminale widzą tylko własną historię, ale nowe widzą chronologicznie dokładną listę poleceń.
Oli
8
@Oli napisał: „Nie mogę wymyślić inteligentnego sposobu, aby to zrobić, gdy istniejące terminale widzą tylko własną historię, ale nowe widzą chronologicznie dokładną listę poleceń”. Jak o (niedoświadczony) export PROMPT_COMMAND="history -a; $PROMPT_COMMAND". Istniejące powłoki dodadzą każde polecenie do pliku historii, aby nowe powłoki mogły je zobaczyć, ale pokażą tylko własne historie.
Chris Page
2
Czy chcesz, aby historia była przechowywana osobno, czy wszystkie połączone w jeden plik historii?
kbyrd
3
Krótka odpowiedź brzmi: nie jest przeznaczony dla programistów bash. Rozwiązania oparte na płukaniu, a następnie ponownym przeczytaniu historii prawdopodobnie działają, ale strzeżcie się Shlemiela Malarza . Krótko mówiąc: ilość pracy przetwarzania między poszczególnymi poleceniami jest proporcjonalna do wielkości historii.
Stéphane Gourichon,

Odpowiedzi:

329

Dodaj następujące elementy do ~ / .bashrc

# Avoid duplicates
export HISTCONTROL=ignoredups:erasedups  
# When the shell exits, append to the history file instead of overwriting it
shopt -s histappend

# After each command, append to the history file and reread it
export PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"
Pablo R.
źródło
20
Problem z tym rozwiązaniem PROMPT_COMMAND polega na tym, że liczby dla każdego elementu historii zmieniają się po każdym poleceniu :(. Na przykład, jeśli wpiszesz history i 1) ls 2) rm, to zrobisz! 1, aby powtórzyć 1, numer historii może się zmienić i może uruchomić polecenie rm ...
Chris Kimpton
2
Kiedy to robię, inne otwarte terminale nie mają ostatnio wprowadzonego polecenia po naciśnięciu przycisku „W górę”, dopóki nie wydam polecenia w tym terminalu - czy jest to oczekiwane? Jeśli tak, to czy istnieje sposób na natychmiastowe zmodyfikowanie historii innych terminali?
Suan,
7
@Suan, wydaje mi się to słuszne na podstawie poleceń. Odkryłem, że możemy wydać polecenie zerowe (wystarczy nacisnąć klawisz Enter), aby pobrać historię do aktualizacji.
mędrzec
3
Rzeczywiście history -a(...) nie powoduje kasowania duplikatów zgodnie z tym odpowiedź na pytanie historii Bash „ignoredups” i „erasedups” Ustawianie konflikt ze wspólnej historii całej sesji . Ta odpowiedź podaje również sekwencję history -<option>poleceń, która działa z HISTCONTROL=ignoredups:erasedupsustawieniami.
Piotr Dobrogost
23
Nie ma powodu, aby exportsię HISTCONTROLi PROMPT_COMMANDzmiennych: definiowania ich w .bashrctak zostaną one zdefiniowane w każdej muszli (nawet w tych nieinterakcyjnych, który jest również marnotrawstwem).
dolmen
248

To wszystko, co dotyczy historii .bashrc:

export HISTCONTROL=ignoredups:erasedups  # no duplicate entries
export HISTSIZE=100000                   # big big history
export HISTFILESIZE=100000               # big big history
shopt -s histappend                      # append to history, don't overwrite it

# Save and reload the history after each command finishes
export PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"

Testowane w wersji bash 3.2.17 na Mac OS X 10.5, bash 4.1.7 na 10.6.

kch
źródło
3
Hmm .. Zabija to możliwość użycia $! 34, ponieważ numery poleceń zmieniają się po każdym znaku zachęty. Czy istnieje obejście @Davide @Schof @kch?
5
Użyj tego, aby uzyskać nieskończoną historię: bash wieczną historię . JEDNAK jest to uzupełnienie powyższego kodu, ponieważ nie zostanie ponownie załadowane automatycznie.
7
Do Twojej wiadomości Żadne z wymienionych tutaj rozwiązań nie może rozwiązać następującego problemu. Mam dwa okna powłoki A i B. W oknie powłoki A uruchamiam sleep 9999i (nie czekając na zakończenie snu) w oknie powłoki B chcę widzieć sleep 9999historię bash.
pkt.
1
@pts Ja również dążyłem do zachowania na żywo, ale potem zdałem sobie sprawę, że wygodniej jest mieć historie specyficzne dla terminali, które ułatwiają pracę nad różnymi rzeczami w różnych terminalach. Uważam, że jest to bardzo przydatne: stackoverflow.com/questions/338285/#answer-7449399 Na tej podstawie stworzyłem alias o nazwie, hrefktóry odświeża historię mojego bieżącego terminala i czyści plik historii w tym procesie. Ilekroć otwieram nowy terminal, czyszczenie / synchronizacja jest wykonywana w moim pliku bashrc, więc nowy terminal ma najnowszą historię. Używam tego wraz zhistory -a
trusktr
6
exportZmienne nie mają powodu : definiujesz je, .bashrcwięc będą zdefiniowane w każdej powłoce (nawet w nieinteraktywnych, co również jest marnotrawstwem)
dolmen
118

Oto moja próba udostępniania historii sesji Bash. Umożliwi to dzielenie się historią między sesjami bash w taki sposób, że licznik historii nie zostanie pomieszany, a ekspansja historii jak !numberbędzie działać (z pewnymi ograniczeniami).

Korzystanie z wersji Bash 4.1.5 pod Ubuntu 10.04 LTS (Lucid Lynx).

HISTSIZE=9000
HISTFILESIZE=$HISTSIZE
HISTCONTROL=ignorespace:ignoredups

_bash_history_sync() {
    builtin history -a         #1
    HISTFILESIZE=$HISTSIZE     #2
    builtin history -c         #3
    builtin history -r         #4
}

history() {                  #5
    _bash_history_sync
    builtin history "$@"
}

PROMPT_COMMAND=_bash_history_sync

Wyjaśnienie:

  1. Dołącz właśnie wprowadzoną linię do $HISTFILE(domyślnie jest .bash_history). Spowoduje to $HISTFILEwzrost o jedną linię.

  2. Ustawienie zmiennej specjalnej $HISTFILESIZEna pewną wartość spowoduje, że Bash $HISTFILEnie będzie dłużej niż $HISTFILESIZElinie, usuwając najstarsze wpisy.

  3. Wyczyść historię uruchomionej sesji. Spowoduje to zmniejszenie licznika historii o kwotę $HISTSIZE.

  4. Przeczytaj zawartość $HISTFILEi włóż je do bieżącej historii uruchomionych sesji. podniesie to licznik historii o liczbę linii w $HISTFILE. Zauważ, że liczba wierszy $HISTFILEniekoniecznie $HISTFILESIZE.

  5. history()Funkcja nadpisuje wbudowane historia, aby upewnić się, że historia jest zsynchronizowany zanim zostanie wyświetlona. Jest to konieczne do rozszerzenia historii według liczb (więcej na ten temat później).

Więcej wyjaśnień:

  • Krok 1 zapewnia, że ​​polecenie z bieżącej uruchomionej sesji zostanie zapisane w pliku historii globalnej.

  • Krok 4 zapewnia, że ​​polecenia z innych sesji zostaną wczytane do bieżącej historii sesji.

  • Ponieważ krok 4 podniesie licznik historii, musimy w jakiś sposób zmniejszyć licznik. Odbywa się to w kroku 3.

  • W kroku 3 licznik historii jest zmniejszany o $HISTSIZE. W kroku 4 licznik historii jest podnoszony o liczbę linii w $HISTFILE. W kroku 2 upewniamy się, że liczba wierszy $HISTFILEjest dokładnie $HISTSIZE(to znaczy, że $HISTFILESIZEmusi być taka sama jak $HISTSIZE).

O ograniczeniach ekspansji historii:

Korzystając z rozszerzania historii według numeru, należy zawsze wyszukać numer bezpośrednio przed użyciem. Oznacza to, że nie trzeba wyświetlać monitu między wyszukiwaniem numeru a jego użyciem. Zazwyczaj oznacza to brak Enter i brak ctrl + c.

Zasadniczo, gdy masz więcej niż jedną sesję Bash, nie ma żadnej gwarancji, że rozwinięcie historii według liczby zachowa swoją wartość między dwoma ekranami zachęty Bash. Ponieważ kiedy PROMPT_COMMANDjest wykonywana, historia wszystkich innych sesji Bash jest zintegrowana z historią bieżącej sesji. Jeśli jakakolwiek inna sesja bash ma nowe polecenie, numery historii bieżącej sesji będą inne.

Uważam to ograniczenie za uzasadnione. I tak muszę za każdym razem sprawdzać liczbę, ponieważ nie pamiętam dowolnych liczb historycznych.

Zwykle używam rozszerzenia historii według liczb w ten sposób

$ history | grep something #note number
$ !number

Polecam użycie następujących opcji Bash.

## reedit a history substitution line if it failed
shopt -s histreedit
## edit a recalled history line before executing
shopt -s histverify

Dziwne błędy:

Uruchomienie polecenia historii potokowanej do czegokolwiek spowoduje dwukrotne wyświetlenie tego polecenia w historii. Na przykład:

$ history | head
$ history | tail
$ history | grep foo
$ history | true
$ history | false

Wszystkie zostaną wyświetlone w historii dwukrotnie. Nie mam pojęcia dlaczego.

Pomysły na ulepszenia:

  • Zmodyfikuj funkcję, _bash_history_sync()aby nie działała za każdym razem. Na przykład nie powinien zostać wykonany po CTRL+Cznaku zachęty. Często używam CTRL+Cdo odrzucenia długiej linii poleceń, gdy decyduję, że nie chcę jej wykonywać. Czasami muszę użyć, CTRL+Caby zatrzymać skrypt zakończenia Bash.

  • Polecenia z bieżącej sesji powinny zawsze być najnowszymi w historii bieżącej sesji. Spowoduje to również efekt uboczny, że dany numer historii zachowuje swoją wartość dla wpisów historii z tej sesji.

lesmana
źródło
1
Dlaczego nie „historia -n” (przeładowanie linii jeszcze nie załadowanych) zamiast „historia -c; historia -r”?
Graham
@Graham: Nie chciałem używać, history -nponieważ to popsuło licznik historii. Ponadto okazało history -nsię , że jestem zbyt zawodny.
lesmana
1
Jedna wada: polecenia z ciągami zawierającymi wiele wierszy są zwykle zachowywane w bieżącej sesji. Dzięki tej sztuczce są one natychmiast dzielone na pojedyncze linie. Użycie -n dla -c -r nie pomaga, podobnie jak cmdhist ani litist. Nie sądzę, aby w tym momencie istniało obejście.
Jo Liss,
24
Po wypróbowaniu tego przez pewien czas faktycznie odkryłem, że uruchamianie tylko history -abez -ci -rjest lepsze pod względem użyteczności (choć nie jest to pytanie zadawane). Oznacza to, że uruchamiane polecenia są dostępne natychmiast w nowych powłokach, nawet przed wyjściem z bieżącej powłoki, ale nie w równoległych uruchomionych powłokach. W ten sposób Arrow-Up wciąż wybiera ostatnie polecenia z bieżącej sesji , co wydaje mi się mniej skomplikowane.
Jo Liss,
wyjątkowo dobra odpowiedź, działa niezawodnie w przeciwieństwie do bardziej powszechnej „historii -a; historii -n”
RichVel
42

Nie znam żadnego sposobu używania bash. Ale to jedna z najpopularniejszych funkcji zsh.
Osobiście wolę zshponad, bashwięc polecam spróbować.

Oto część mojej, .zshrcktóra dotyczy historii:

SAVEHIST=10000 # Number of entries
HISTSIZE=10000
HISTFILE=~/.zsh/history # File
setopt APPEND_HISTORY # Don't erase history
setopt EXTENDED_HISTORY # Add additional data to history like timestamp
setopt INC_APPEND_HISTORY # Add immediately
setopt HIST_FIND_NO_DUPS # Don't show duplicates in search
setopt HIST_IGNORE_SPACE # Don't preserve spaces. You may want to turn it off
setopt NO_HIST_BEEP # Don't beep
setopt SHARE_HISTORY # Share history between session/terminals
Maciej Piechotka
źródło
16

Aby to zrobić, musisz dodać dwa wiersze do ~/.bashrc:

shopt -s histappend
PROMPT_COMMAND="history -a;history -c;history -r;$PROMPT_COMMAND"

Od man bash:

Jeśli włączona jest opcja powłoki histappend (patrz opis shopt w POLECENIA WBUDOWANE POWŁOKI poniżej), wiersze są dołączane do pliku historii, w przeciwnym razie plik historii zostanie nadpisany.

Chris Down
źródło
10

Możesz edytować monit BASH, aby uruchomić „history -a” i „history -r”, które zaproponował Muerr:

savePS1=$PS1

(na wypadek, gdybyś coś popsuł, co jest prawie gwarantowane)

PS1=$savePS1`history -a;history -r`

(zwróć uwagę, że są to tyknięcia wstecz; będą one uruchamiać historię -a i historię -r dla każdego monitu. Ponieważ nie wypisują żadnego tekstu, twoje monity pozostaną niezmienione.

Po skonfigurowaniu zmiennej PS1 tak, jak chcesz, ustaw ją na stałe w pliku ~ / .bashrc.

Jeśli chcesz wrócić do pierwotnego monitu podczas testowania, wykonaj:

PS1=$savePS1

Przeprowadziłem podstawowe testy tego, aby upewnić się, że to działa, ale nie mogę rozmawiać z żadnymi efektami ubocznymi, które pojawiają się history -a;history -rprzy każdym pytaniu.

Schof
źródło
2
Rozwiązanie kch działa lepiej niż moje. Teraz używam jego rozwiązania w moim .bashrc.
9

Jeśli potrzebujesz rozwiązania do synchronizacji historii bash lub zsh, które również rozwiązuje problem poniżej, zobacz go na stronie http://ptspts.blogspot.com/2011/03/how-to-automatically-synchronize-shell.html

Problem jest następujący: Mam dwa okna powłoki A i B. W oknie powłoki A uruchamiam sleep 9999i (bez oczekiwania na zakończenie snu) w oknie powłoki B chcę widzieć sleep 9999historię bash.

Powodem, dla którego większość innych rozwiązań tutaj nie rozwiązuje tego problemu, jest to, że zapisują zmiany historii w pliku historii przy użyciu PROMPT_COMMANDlub PS1oba z nich są wykonywane zbyt późno, dopiero po zakończeniu sleep 9999polecenia.

pkt
źródło
1
To dobre rozwiązanie, ale mam kilka pytań. 1. Czy mogę użyć oryginalnego pliku .bash_history, nie chcę, aby w moim $ HOME istniał inny plik historii bash 2. Być może powinieneś rozważyć ustawienie repo github.
weynhamz,
Wygląda na to, że hak debugowania jest w konflikcie z bashdb, a za każdym razem, gdy rozpoczynam sesję bash, wynik wyjściowy. `` `bash debugger, bashdb, release 4.2-0.8 Copyright 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Rocky Bernstein To bezpłatne oprogramowanie, objęte Powszechną Licencją Publiczną GNU, i zapraszamy do zmienić go i / lub rozpowszechniać jego kopie pod pewnymi warunkami. ** Wewnętrzny błąd debugowania _Dbg_is_file (): argument pliku null bash: _Dbg_filenames [pełna nazwa]: zły indeks tablicy tablicowej ``
weynhamz
@Techlive Zheng: 1. Oryginalna .bash_history jest celowo nieobsługiwana, ponieważ .merged_bash_history używa innego formatu pliku, więc w przypadku, gdy .merged_bash_history nie załaduje się poprawnie, bash przypadkowo nie zablokuje zgromadzonej historii. Solidność z założenia pozostanie niezmieniona. 2. Repozytorium github jest ogólnie dobrym pomysłem, ale nie mam czasu na utrzymanie go w tym projekcie, więc nie robię tego. - Tak, koliduje z bashdb i nie ma łatwego rozwiązania (używają tych samych haków). Nie planuję pracować nad poprawką, ale akceptuję łatki.
pkt
Dobrze dziękuję. Wymyśliłem znacznie prostsze i lepsze zasysanie.
weynhamz,
@TechliveZheng: Czy podzieliłbyś się z nami swoim prostym i lepszym rozwiązaniem, abyśmy wszyscy mogli się z niego uczyć? (Jeśli tak, proszę dodać odpowiedź do pytania.)
pkt.
8

Możesz użyć, history -aaby dołączyć historię bieżącej sesji do pliku histogramu, a następnie użyć history -rna innych terminalach, aby odczytać plik histogramu. 

jtimberman
źródło
8

Tak, w końcu denerwowało mnie to, że znalazłem dobre rozwiązanie:

# Write history after each command
_bash_history_append() {
    builtin history -a
}
PROMPT_COMMAND="_bash_history_append; $PROMPT_COMMAND"

To coś w rodzaju połączenia tego, co zostało powiedziane w tym wątku, z tym wyjątkiem, że nie rozumiem, dlaczego po każdym poleceniu miałbyś przeładowywać historię globalną. Bardzo rzadko dbam o to, co dzieje się w innych terminalach, ale zawsze uruchamiam serię poleceń, powiedzmy w jednym terminalu:

make
ls -lh target/*.foo
scp target/artifact.foo vm:~/

(Uproszczony przykład)

A w innym:

pv ~/test.data | nc vm:5000 >> output
less output
mv output output.backup1

Nie ma mowy, żebym chciał udostępnić polecenie

Yarek T.
źródło
1
Powodem, dla którego przeładowujesz historię po każdym poleceniu jest to, że jest to zachowanie wymagane przez pytanie (a więc tak naprawdę nie odpowiada na postawione pytanie).
Michael Homer,
2
@MichaelHomer Fair point. Nie wahaj się głosować, aby odpowiedź pozostała na dole, jednak spiszę to do PO, nie zdając sobie sprawy z tego, jak złe byłoby pożądane zachowanie i fakt, że jest to bardzo trudne do odpowiedzi pytanie.
Yarek T
3
Op tutaj, tak, to uczciwy kompromis. Moją główną skargą jest to, że traciłem historię. To powinno temu zapobiec, nawet jeśli nie oznacza to natychmiastowych aktualizacji w ramach jednoczesnych sesji.
Oli
7

Oto alternatywa, której używam. Jest to uciążliwe, ale rozwiązuje problem, o którym wspominał @axel_c, w którym czasami możesz chcieć mieć osobne wystąpienie historii w każdym terminalu (jeden dla make, jeden dla monitorowania, jeden dla vima itp.).

Trzymam osobny dołączony plik historii, który stale aktualizuję. Mam następujące mapowanie na skrót:

history | grep -v history >> ~/master_history.txt

Spowoduje to dołączenie całej historii z bieżącego terminala do pliku o nazwie master_history.txt w katalogu domowym.

Mam również osobny skrót do przeszukiwania głównego pliku historii:

cat /home/toby/master_history.txt | grep -i

Używam cat | grep, ponieważ pozostawia kursor na końcu, aby wprowadzić moje wyrażenie regularne. Mniej brzydkim sposobem na to byłoby dodanie kilku skryptów do ścieżki, aby wykonać te zadania, ale skróty klawiszowe działają dla moich celów. Od czasu do czasu ściągam historię z innych hostów, nad którymi pracowałem, i dołączam tę historię do mojego pliku master_history.txt.

Zawsze miło jest móc szybko wyszukać i znaleźć ten trudny regex, którego użyłeś lub ten dziwny perlowy liniowiec, który wymyśliłeś 7 miesięcy temu.

Toby
źródło
6

Mogę zaoferować poprawkę dla tego ostatniego: upewnij się, że zmienna env HISTCONTROL nie określa „ignorespace” (lub „ignoreboth”).

Ale odczuwam twój ból podczas wielu jednoczesnych sesji. Po prostu nie radzi sobie dobrze w bash.

jmanning2k
źródło
6

Oto moja rozszerzeniem @ lesmana za odpowiedź . Główną różnicą jest to, że współbieżne okna nie współużytkują historii. Oznacza to, że możesz dalej pracować w swoich oknach, bez konieczności ładowania kontekstu z innych okien do twoich bieżących okien.

Jeśli jednoznacznie wpiszesz „historia”, LUB jeśli otworzysz nowe okno, otrzymasz historię ze wszystkich poprzednich okien.

Ponadto używam tej strategii do archiwizowania każdego polecenia wpisanego kiedykolwiek na moim komputerze.

# Consistent and forever bash history
HISTSIZE=100000
HISTFILESIZE=$HISTSIZE
HISTCONTROL=ignorespace:ignoredups

_bash_history_sync() {
  builtin history -a         #1
  HISTFILESIZE=$HISTSIZE     #2
}

_bash_history_sync_and_reload() {
  builtin history -a         #1
  HISTFILESIZE=$HISTSIZE     #2
  builtin history -c         #3
  builtin history -r         #4
}

history() {                  #5
  _bash_history_sync_and_reload
  builtin history "$@"
}

export HISTTIMEFORMAT="%y/%m/%d %H:%M:%S   "
PROMPT_COMMAND='history 1 >> ${HOME}/.bash_eternal_history'
PROMPT_COMMAND=_bash_history_sync;$PROMPT_COMMAND
rubel
źródło
5

Zdecydowałem się umieścić historię w pliku na plik, ponieważ wiele osób może pracować na tym samym serwerze - oddzielenie poleceń każdej sesji ułatwia audyt.

# Convert /dev/nnn/X or /dev/nnnX to "nnnX"
HISTSUFFIX=`tty | sed 's/\///g;s/^dev//g'`
# History file is now .bash_history_pts0
HISTFILE=".bash_history_$HISTSUFFIX"
HISTTIMEFORMAT="%y-%m-%d %H:%M:%S "
HISTCONTROL=ignoredups:ignorespace
shopt -s histappend
HISTSIZE=1000
HISTFILESIZE=5000

Historia wygląda teraz następująco:

user@host:~# test 123
user@host:~# test 5451
user@host:~# history
1  15-08-11 10:09:58 test 123
2  15-08-11 10:10:00 test 5451
3  15-08-11 10:10:02 history

Pliki wyglądają następująco:

user@host:~# ls -la .bash*
-rw------- 1 root root  4275 Aug 11 09:42 .bash_history_pts0
-rw------- 1 root root    75 Aug 11 09:49 .bash_history_pts1
-rw-r--r-- 1 root root  3120 Aug 11 10:09 .bashrc
Litch
źródło
3

Wskażę tutaj jeden problem

export PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"

i

PROMPT_COMMAND="$PROMPT_COMMAND;history -a; history -n"

Jeśli uruchomisz source ~ / .bashrc, $ PROMPT_COMMAND będzie podobny

"history -a; history -c; history -r history -a; history -c; history -r"

i

"history -a; history -n history -a; history -n"

Powtórzenie to występuje przy każdym uruchomieniu „source ~ / .bashrc”. Możesz sprawdzić PROMPT_COMMAND po każdym uruchomieniu „source ~ / .bashrc”, uruchamiając „echo $ PROMPT_COMMAND”.

Widać, że niektóre polecenia są najwyraźniej zepsute: „history -n history -a”. Ale dobrą wiadomością jest to, że nadal działa, ponieważ inne części nadal tworzą prawidłową sekwencję poleceń (po prostu wiąże się to z dodatkowymi kosztami z powodu powtarzalnego wykonywania niektórych poleceń. I nie jest tak czyste).

Osobiście korzystam z następującej prostej wersji:

shopt -s histappend
PROMPT_COMMAND="history -a; history -c; history -r"

który ma większość funkcji, a nie ma takiego problemu jak wspomniano powyżej.

Kolejną kwestią do zrobienia jest: naprawdę nie ma magii . PROMPT_COMMAND to zwykła zmienna środowiskowa bash. Polecenia w nim wykonywane są wykonywane przed wyświetleniem monitu bash (znak $). Na przykład twój PROMPT_COMMAND to „echo 123”, a ty uruchamiasz „ls” w swoim terminalu. Efekt jest podobny do uruchomienia „ls; echo 123”.

$ PROMPT_COMMAND="echo 123"

wyjście (Podobnie jak uruchomienie „PROMPT_COMMAND =„ echo 123 ”; $ PROMPT_COMMAND”):

123

Uruchom następujące czynności:

$ echo 3

wynik:

3
123

„history -a” służy do zapisywania poleceń historii w pamięci do ~ / .bash_history

„history -c” służy do usuwania poleceń historii z pamięci

„history -r” służy do odczytu poleceń historii z ~ / .bash_history do pamięci

Zobacz wyjaśnienie polecenia historii tutaj: http://ss64.com/bash/history.html

PS: Jak zauważyli inni użytkownicy, eksport nie jest konieczny. Zobacz: za pomocą eksportu w .bashrc

fstang
źródło
2

Napisałem skrypt do ustawiania pliku historii na sesję lub zadania w oparciu o następujące.

        # write existing history to the old file
        history -a

        # set new historyfile
        export HISTFILE="$1"
        export HISET=$1

        # touch the new file to make sure it exists
        touch $HISTFILE
        # load new history file
        history -r $HISTFILE

Nie trzeba zapisywać każdego polecenia historii, ale zapisuje te, na których mi zależy, i łatwiej je odzyskać niż wykonać każde polecenie. Moja wersja zawiera także listę wszystkich plików historii i umożliwia przeszukiwanie ich wszystkich.

Pełne źródło: https://github.com/simotek/scripts-config/blob/master/hiset.sh

simotek
źródło
2

Oto rozwiązanie, które nie miesza historii z poszczególnych sesji!

Zasadniczo należy przechowywać historię każdej sesji osobno i odtwarzać ją przy każdym monicie. Tak, zużywa więcej zasobów, ale nie jest tak powolny, jak może się wydawać - opóźnienie zaczyna być zauważalne tylko, jeśli masz więcej niż 100000 wpisów historii.

Oto podstawowa logika:

# on every prompt, save new history to dedicated file and recreate full history
# by reading all files, always keeping history from current session on top.
update_history () {
  history -a ${HISTFILE}.$$
  history -c
  history -r
  for f in `ls ${HISTFILE}.[0-9]* | grep -v "${HISTFILE}.$$\$"`; do
    history -r $f
  done
  history -r "${HISTFILE}.$$"
}
export PROMPT_COMMAND='update_history'

# merge session history into main history file on bash exit
merge_session_history () {
  cat ${HISTFILE}.$$ >> $HISTFILE
  rm ${HISTFILE}.$$
}
trap merge_session_history EXIT

Zobacz listę, aby uzyskać pełne rozwiązanie, w tym niektóre zabezpieczenia i optymalizacje wydajności.

Jan Warchoł
źródło
1

Działa to dla ZSH

##############################################################################
# History Configuration for ZSH
##############################################################################
HISTSIZE=10000               #How many lines of history to keep in memory
HISTFILE=~/.zsh_history     #Where to save history to disk
SAVEHIST=10000               #Number of history entries to save to disk
#HISTDUP=erase               #Erase duplicates in the history file
setopt    appendhistory     #Append history to the history file (no overwriting)
setopt    sharehistory      #Share history across terminals
setopt    incappendhistory  #Immediately append to the history file, not just when a term is killed
Mulki
źródło
niestety pytanie dotyczy wyłącznie bash :-)
Jaleks,
1
jest to pierwszy wynik w Google, gdy szukam również zsh ... Pomyślałem, że może pomóc
Mulki
3
Powinieneś zadać nowe pytanie ~ Zachowaj historię zsh w wielu oknach terminali, zakładając, że jedno jeszcze nie istnieje. Zupełnie w porządku - nawet zachęcanym - jest udzielenie odpowiedzi na własne pytanie, jeśli jest to dobre pytanie.
Oli
1

Od dawna chciałem tego, zwłaszcza możliwości pobrania polecenia według miejsca, w którym zostało uruchomione w celu ponownego uruchomienia w nowym projekcie (lub znalezienia katalogu za pomocą polecenia). Więc zestawiłem to narzędzie , które łączy poprzednie rozwiązania do przechowywania globalnej historii CLI z interaktywnym narzędziem grepping o nazwie percol (mapowane na C ^ R). Nadal jest zręczny na pierwszej maszynie, z której zacząłem go używać, teraz z ponad 2-letnią historią CLI.

Nie bałagan z lokalną historią CLI, jeśli chodzi o klawisze strzałek, ale pozwala dość łatwo uzyskać dostęp do historii globalnej (którą można również odwzorować na coś innego niż C ^ R)

Gordon Wells
źródło
to jest dla zsh?
sjas
1
tak, początkowo zrobiłem to dla Zsh. Ale działa też na bash i ryby. Daj mi znać, czy to działa, czy nie. Nie zmieniłem tego od dłuższego czasu i nie jestem pewien, jak jasno zrozumiałem instrukcje instalacji
Gordon Wells,
1

Ponieważ wolę nieskończoną historię zapisaną w pliku niestandardowym. Tworzę tę konfigurację na podstawie https://stackoverflow.com/a/19533853/4632019 :

export HISTFILESIZE=
export HISTSIZE=
export HISTTIMEFORMAT="[%F %T] "

export HISTFILE=~/.bash_myhistory
PROMPT_COMMAND="history -a; history -r; $PROMPT_COMMAND"
Eugen Konkov
źródło
-1

Oto fragment mojego pliku .bashrc i krótkie objaśnienia, gdy są potrzebne:

# The following line ensures that history logs screen commands as well
shopt -s histappend

# This line makes the history file to be rewritten and reread at each bash prompt
PROMPT_COMMAND="$PROMPT_COMMAND;history -a; history -n"
# Have lots of history
HISTSIZE=100000         # remember the last 100000 commands
HISTFILESIZE=100000     # start truncating commands after 100000 lines
HISTCONTROL=ignoreboth  # ignoreboth is shorthand for ignorespace and     ignoredups

HISTFILESIZE i HISTSIZE są osobistymi preferencjami i możesz je zmieniać według własnych upodobań.

Hopping Bunny
źródło