Nejprve to není duplikát existujících vláken na SE. Přečetl jsem si tato dvě vlákna ( 1. , 2. ) o lepší historii bash, ale žádná z odpovědí nefunguje - - Mimochodem, jsem na Fedoře 15.
Do souboru .bashrc
V uživatelském adresáři (/ home/aahan /) jsem přidal následující a nefunguje to. Někdo má tušení?
HISTCONTROL=ignoredups:erasedups # no duplicate entries
HISTSIZE=1000 # custom history size
HISTFILESIZE=100000 # custom history file size
shopt -s histappend # append to history, don't overwrite it
Prompt_COMMAND="history -a; history -c; history -r; $Prompt_COMMAND" # Save and reload the history after each command finishes
Dobře to je to, co chci s bash historií (priorita):
To je vlastně opravdu zajímavé chování a přiznávám, že jsem otázku na začátku velmi podcenil. Nejprve však fakta:
Funkci lze dosáhnout několika způsoby, i když každý funguje trochu jinak. Všimněte si, že v každém případě, aby historie byla „přenesena“ na jiný terminál (aktualizována), je třeba stisknout Enter v terminálu, kde chce načíst historii.
možnost 1:
shopt -s histappend
HISTCONTROL=ignoredups
Prompt_COMMAND="history -a; history -n; $Prompt_COMMAND"
To má dvě nevýhody:
možnost 2:
HISTCONTROL=ignoredups
Prompt_COMMAND="history -a; history -c; history -r; $Prompt_COMMAND"
(Ano, není třeba shopt -s histappend
A ano, je to musí být history -c
Uprostřed Prompt_COMMAND
) Tato verze má také dvě důležité nevýhody :
history
může poskytnout falešný výstup - viz níže.[Upravit]"A vítězem je ..."
možnost 3:
HISTCONTROL=ignoredups:erasedups
shopt -s histappend
Prompt_COMMAND="history -n; history -w; history -c; history -r; $Prompt_COMMAND"
Je to tak daleko, jak to jde. Je to volba pouze, aby současně fungovaly jak erasedups
, tak i společná historie. Toto je pravděpodobně konečné řešení ke všem vašim problémům, Aahane.
Jak jsem již zmínil, každé z výše uvedených řešení funguje jinak. Ale nejvíce zavádějící interpretace toho, jak nastavení funguje, vychází z analýzy výstupu příkazu history
. V mnoha případech může příkaz poskytnout výstup false. Proč? Protože provádí se před posloupnost dalších history
příkazů obsažených v Prompt_COMMAND
! Při použití druhé nebo třetí možnosti však lze sledovat změny obsahu .bash_history
(například pomocí watch -n1 "tail -n20 .bash_history"
) a zjistit, jaká je skutečná historie.
Všechno spočívá ve způsobu erasedups
funguje. Jak uvádí bash manual, "(...) erasedups
způsobí, že všechny předchozí řádky odpovídající aktuálnímu řádku budou odstraněny ze seznamu historie, než bude tento řádek uložen". To je tedy to, co OP chtěl (a nejen, jak jsem si dříve myslel, aby se neobjevovaly duplikáty postupně). Zde je důvod, proč každý z příkazů history -.
Musí nebo nemůže být v Prompt_COMMAND
:
history -n
musí, aby tam byl před history -w
A přečetl z .bash_history
Příkazy uložené z jakéhokoli jiného terminálu,
history -w
musí být tam, aby se historie uložila do souboru a vymazala duplikáty,
history -a
nesmí být tam umístěny místo history -w
, Protože to nespouští mazání duplikátů,
history -c
Je také potřeba, protože zabraňuje přetažení vyrovnávací paměti historie po každém příkazu,
a konečně, history -r
je potřeba k obnovení vyrovnávací paměti historie ze souboru, čímž se nakonec historie sdílí přes terminálové relace.
V příkazu Prompt používáte -c
přepínač. Z man bash
:
- c Vymazání seznamu historie odstraněním všech položek
Chcete-li sdílet svou historii se všemi otevřenými terminály, můžete použít -n
:
- n Přečíst řádky historie, které ještě nebyly načteny ze souboru historie, do aktuálního seznamu historie. Toto jsou řádky připojené k souboru historie od začátku aktuální relace bash.
Výchozí velikost je také v manuálu:
HISTSIZE Počet příkazů k zapamatování v historii příkazů (viz HISTORIE níže). Výchozí hodnota je 500.
Chcete-li uložit víceřádkové příkazy:
Volba cmdhist Shell, pokud je povolena, způsobí, že se Shell pokusí uložit každý řádek víceřádkového příkazu do stejné položky historie, v případě potřeby přidat středníky, aby se zachovala syntaktická správnost. Možnost lithist Shell způsobí, že prostředí Shell uloží příkaz s vloženými novými řádky namísto středníků.
Také byste neměli předmluvit příkazy HIST * s export
- jsou to proměnné pouze pro bash, nikoli proměnné prostředí: HISTCONTROL=ignoredups:erasedups
je dostačující.
To je to, s čím jsem přišel a jsem s tím zatím spokojený…
alias hfix='history -n && history | sort -k2 -k1nr | uniq -f1 | sort -n | cut -c8- > ~/.tmp$$ && history -c && history -r ~/.tmp$$ && history -w && rm ~/.tmp$$'
HISTCONTROL=ignorespace
shopt -s histappend
shopt -s extglob
HISTSIZE=1000
HISTFILESIZE=2000
export HISTIGNORE="!(+(*\ *))"
Prompt_COMMAND="hfix; $Prompt_COMMAND"
POZNÁMKY:
HISTIGNORE
ignoruje všechny příkazy, které nemají argumenty. Někteří lidé to nemusí být žádoucí a mohou být vynecháni.Použijte místo toho:
HISTCONTROL=ignoreboth
Nefunguje to, protože zapomenete na:
-n read all history lines not already read from the history file and append them to the history list
Ale zdá se, že history -n
Je jen buggy, když je export HISTCONTROL=ignoreboth:erasedups
V platnosti.
Umožňuje experimentovat:
$ Prompt_COMMAND=
$ export HISTCONTROL=ignoreboth:erasedups
$ export HISTFILE=~/.bash_myhistory
$ HISTIGNORE='history:history -w'
$ history -c
$ history -w
Zde zapneme mazání duplikátů, přepneme historii na vlastní soubor, vymažeme historii. Po dokončení všech příkazů máme prázdný soubor historie a jeden příkaz v aktuální historii.
$ history
$ cat ~/.bash_myhistory
$ history
$ 1 [2019-06-17 14:57:19] cat ~/.bash_myhistory
Otevřete druhý terminál a spusťte také těchto šest příkazů. Potom:
$ echo "X"
$ echo "Y"
$ history -w
$ history
1 [2019-06-17 15:00:21] echo "X"
2 [2019-06-17 15:00:23] echo "Y"
Nyní má vaše aktuální historie dva příkazy a soubor historie má:
#1560772821
echo "X"
#1560772823
echo "Y"
Zpět na první terminál:
$ history -n
$ history
1 [2019-06-17 14:57:19] cat ~/.bash_myhistory
2 [2019-06-17 15:03:12] history -n
Huh ... žádný z příkazů echo
není přečten. Přepněte znovu na druhý terminál a:
$ echo "Z"
$ history -w
Nyní je soubor historie:
#1560772821
echo "X"
#1560772823
echo "Y"
#1560773057
echo "Z"
Přepněte znovu na první terminál:
$ history -n
$ history
1 [2019-06-17 14:57:19] cat ~/.bash_myhistory
2 [2019-06-17 15:03:12] history -n
echo "Z"
Můžete vidět, že příkaz echo "Z"
Je sloučen s history -n
.
Další chyba je, protože příkazy jsou čteny z historie podle čísla příkazu a ne podle času příkazu, myslím. Očekávám, že se v historii objevily další příkazy echo
Šel jsem zde s kombinací odpovědí:
$ ./.secretfunction -user myuser -password mypassword
nebude uloženo, protože začíná mezerou.history*
a exit
to HISTIGNORE jen proto, aby tyto příkazy včetně čehokoli minulé historie jako history | grep awesomecommand
odtamtud, protože bych to normálně nechtěl. Můžete přidat další, například: odhlášení, fg, bg atd.HISTCONTROL=ignoreboth:erasedups:ignorespace
HISTIGNORE="history*:exit"
HISTFILE=~/.bash_history/.$(hostname)_history
shopt -s histappend
function historymerge {
history -n; history -w; history -c; history -r;
}
trap historymerge EXIT
Prompt_COMMAND="history -a; $Prompt_COMMAND"
Pozdravte svůj ~/pro Prompt_COMMAND, abyste se ujistili, že již nejste upraveni historií -a. Také jsem přidal formát TIME/DATE HISTTIMEFORMAT="%x %r %Z "
Líbilo se mi, ale nezahrnul jsem do výše uvedeného bloku, protože to je citlivé na národní prostředí.
erasedups nezastřihává (jako v některých jazycích chomp) úvodní a koncové mezery. Toto je chyba. Vymazané položky také neodstraní všechny předchozí položky.
Použití kombinace možnosti 3 rozcietrzewiacz s výstupní pascí umožní terminálům, které udržují své vlastní nezávislé relace historie, které se těsně přibližují. Zdá se, že dokonce funguje dobře s více relacemi napříč různými stroji sdílejícími vzdálený domovský adresář.
export HISTSIZE=5000
export HISTFILESIZE=5000
export HISTCONTROL=ignorespace:erasedups
shopt -s histappend
function historymerge {
history -n; history -w; history -c; history -r;
}
trap historymerge EXIT
Prompt_COMMAND="history -a; $Prompt_COMMAND"
Funkce historymerge
načte řádky mimo relaci ze souboru historie, zkombinuje je s historií relací, zapíše nový soubor historie s deduplikací (čímž potlačí všechny dříve přidané duplicitní řádky) a načte historii.
Vedení history -a
v Prompt minimalizuje potenciál pro ztrátu historie, protože aktualizuje soubor historie bez deduplikace při každém příkazu.
A konečně, trap spouští historymerge
na relaci blízko pro aktuální aktuální soubor historie s posledními příkazy z poslední uzavřené relace bublaly na konec souboru (myslím).
Díky tomu bude mít každá relace terminálu svou vlastní nezávislou historii od spuštění. Zjistil jsem, že je užitečnější, protože mám tendenci mít otevřené různé terminály pro různé úkoly (tedy chci opakovat různé příkazy v každém). Je to také milosrdně jednodušší, než pochopit, že se několik terminálů neustále snaží synchronizovat svou spořádano historii distribuovaným způsobem (přesto to můžete udělat úmyslně pomocí funkce historymerge
s vybranými relacemi nebo všichni).
Všimněte si, že budete chtít, aby vaše velikostní limity byly dostatečně velké, aby udržely požadovanou délku historie plus objem nededuplikovaných řádků, které mohou být přidány všemi souběžně aktivními relacemi. 5000 je pro mě dostačující hlavně díky rozsáhlému použití HISTIGNORE
k odfiltrování spamových příkazů s nízkou hodnotou.