it-swarm-eu.dev

Historie bash: "ignoredups" a "erasedups" nastavení konflikt se společnou historií napříč relacemi

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):

  • neukládejte duplikáty, vymažte všechny stávající
  • okamžitě sdílejte historii se všemi otevřenými terminály
  • vždy připojte historii, ne ji přepisujte
  • ukládat víceřádkové příkazy jako jeden příkaz (ve výchozím nastavení vypnutý)
  • jaká je výchozí velikost historie a velikost souboru historie?
92
its_me

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:

1. Co funguje

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:

    1. Při přihlášení (otevření terminálu) se poslední příkaz ze souboru historie načte dvakrát do vyrovnávací paměti historie aktuálního terminálu;
    2. Vyrovnávací paměti různých terminálů nezůstávají synchronizovány se souborem historie.
  • 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 :

    1. Soubor historie musí být inicializován. Musí obsahovat alespoň jeden neprázdný řádek (může být cokoli).
    2. Příkaz 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.


2. Proč možnost 2 nefunguje (nebo: co opravd nefunguje podle očekávání)?

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.

3. Proč možnost je tak komplikovaná?

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 -nmusí, 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 -wmusí být tam, aby se historie uložila do souboru a vymazala duplikáty,

  • history -anesmí 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.

126
rozcietrzewiacz

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í.

8
jasonwryan

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:

  • Ano, je to komplikované ... ale odstraní všechny duplikáty a přitom zachovává chronologii v každém terminálu!
  • Moje HISTIGNORE ignoruje všechny příkazy, které nemají argumenty. Někteří lidé to nemusí být žádoucí a mohou být vynecháni.
8
user41176

Použijte místo toho:

HISTCONTROL=ignoreboth
1
verndog

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

0
Eugen Konkov

Šel jsem zde s kombinací odpovědí:

  • Chci, aby se moje historie na konci sloučila, takže jsem použil funkci trap.
  • Chci také, aby moje soubory historie byly odděleny hostiteli, takže jsem změnil HISTFILE tak, aby ukazoval na adresář a pojmenované soubory v závislosti na názvu hostitele.
  • Přidal jsem možnost ignorespace, abych mohl psát hesla čistého textu a nechat je, aby se zobrazovaly v historii, např .: $ ./.secretfunction -user myuser -password mypassword nebude uloženo, protože začíná mezerou.
  • Přidal jsem 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.
  • Pak jsem to všechno vložil do svého souboru ~/.bash_aliases, takže to není v rozporu s upgrady, jak se to někdy stalo.
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í.

0
Marlon

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.

0

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.

0
HonoredMule