it-swarm-eu.dev

Jak mohu odstranit duplikáty z mého .bash_history, při zachování pořadí?

Opravdu si užívám použití control+r pro rekurzivní prohledávání historie mých příkazů. Našel jsem několik dobrých možností, které s ním rád používám:

# ignore duplicate commands, ignore commands starting with a space
export HISTCONTROL=erasedups:ignorespace

# keep the last 5000 entries
export HISTSIZE=5000

# append to the history instead of overwriting (good for multiple connections)
shopt -s histappend

Jediným problémem pro mě je, že erasedups smaže pouze sekvenční duplikáty - takže s tímto řetězcem příkazů:

ls
cd ~
ls

Příkaz ls bude skutečně zaznamenán dvakrát. Přemýšlel jsem o pravidelném běhu w/cron:

cat .bash_history | sort | uniq > temp.txt
mv temp.txt .bash_history

Tím by se dosáhlo odstranění duplikátů, ale bohužel by pořadí nebylo zachováno. Pokud soubor sort nejprve neeviduji, nemyslím si, že uniq může fungovat správně.

Jak mohu odstranit duplikáty z mého .bash_history, při zachování pořadí?

Kredit navíc:

Existují nějaké problémy s přepsáním .bash_history soubor skriptem? Pokud například odeberete soubor protokolu Apache, myslím, že musíte poslat signál Nohup/reset pomocí kill, aby bylo možné vyprázdnit připojení k souboru. Pokud tomu tak je v případě .bash_history soubor, možná bych mohl nějak použít ps ke kontrole a ujistit se, že neexistují žádné připojené relace před spuštěním filtrovacího skriptu?

69
cwd

Třídění historie

Tento příkaz funguje jako sort|uniq, ale udržuje linky na místě

nl|sort -k 2|uniq -f 1|sort -n|cut -f 2

V zásadě připojí na každý řádek své číslo. Po sort|uniq- jsou všechny řádky řazeny zpět podle jejich původního pořadí (pomocí pole číslo řádku) a číslo řádku je z řádků odstraněno.

Toto řešení má tu vadu, že není definováno, který zástupce třídy stejných řádků bude činit ve výstupu, a proto není definována jeho pozice v konečném výstupu. Pokud by však měl být vybrán nejnovější zástupce, můžete sort vstup pomocí druhého klíče:

nl|sort -k2 -k 1,1nr|uniq -f1|sort -n|cut -f2

Správa .bash_history

Pro přečtení a zapsání historie můžete použít history -a a history -w.

37
artistoex

Takže jsem hledal stejnou přesnou věc poté, co jsem byl otráven duplikáty, a zjistil jsem, že když upravím svůj ~/.bash_profile (Mac) pomocí:

export HISTCONTROL=ignoreboth:erasedups

Dělá přesně to, co jste chtěli, udržuje pouze poslední příkaz. ignoreboth je vlastně jako dělat ignorespace:ignoredups a to spolu s erasedups provede práci.

Alespoň na mém Mac terminálu s bashem to funguje perfektně. Nalezeno zde na askubuntu.com .

57
sprite

Našel jsem toto řešení ve volné přírodě a testoval:

awk '!x[$0]++'

Při prvním zobrazení konkrétní hodnoty řádku ($ 0) je hodnota x [$ 0] nula.
Hodnota nula je invertována s ! a stane se jedním.
Příkaz, který vyhodnocuje jeden způsobí výchozí akci, kterou je tisk.

Proto poprvé poprvé $0 je vidět, je vytištěno.

Pokaždé (opakuje se) hodnota x[$0] byl zvýšen,
jeho negovaná hodnota je nula a příkaz, který vyhodnocuje na nulu, se nevytiskne.

Chcete-li zachovat poslední opakovanou hodnotu, obráťte historii a použijte stejný awk:

awk '!x[$0]++' ~/.bash_history                 # keep the first value repeated.

tac ~/.bash_history | awk '!x[$0]++' | tac     # keep the last.
21
Clayton Stanley

Rozšíření Claytonovy odpovědi:

tac $HISTFILE | awk '!x[$0]++' | tac | sponge $HISTFILE

tac obrátí soubor, ujistěte se, že jste nainstalovali moreutils, takže máte sponge k dispozici, jinak použijte dočasný soubor.

12
Ali Shakiba

Toto je starý příspěvek, ale trvalý problém pro uživatele, kteří chtějí mít otevřeno více terminálů a mít historii synchronizovanou mezi okny, ale ne duplikovanou.

Moje řešení v .bashrc:

shopt -s histappend
export HISTCONTROL=ignoreboth:erasedups
export Prompt_COMMAND="history -n; history -w; history -c; history -r"
tac "$HISTFILE" | awk '!x[$0]++' > /tmp/tmpfile  &&
                tac /tmp/tmpfile > "$HISTFILE"
rm /tmp/tmpfile
  • volba histappend přidá historii vyrovnávací paměti na konec souboru historie ($ HISTFILE)
  • ignoreboth a erasedups zabrání uložení duplicitních záznamů do $ HISTFILE
  • Příkaz Prompt aktualizuje mezipaměť historie
    • history -n přečte všechny řádky z $ HISTFILE, které se mohly vyskytnout v jiném terminálu od posledního návratu vozíku
    • history -w zapíše aktualizovanou vyrovnávací paměť do $ HISTFILE
    • history -c vymaže buffer, takže nedochází k duplicitě
    • history -r znovu přečte $ HISTFILE a připojí se k nyní prázdné vyrovnávací paměti
  • skript awk ukládá první výskyt každého řádku, na který narazí. tac převrátí a poté převrátí zpět, aby mohl být uložen s nejnovějšími příkazy, které jsou v historii nejnovější
  • rm soubor/tmp

Pokaždé, když otevřete nový Shell, historie vymaže všechny dupy a pokaždé, když narazíte na Enter klíč v jiném okně prostředí/terminálu, aktualizuje tuto historii ze souboru.

7
smilingfrog

Zachovaly by se poslední duplicitní řádky:

Ruby -i -e 'puts readlines.reverse.uniq.reverse' ~/.bash_history
tac ~/.bash_history | awk '!a[$0]++' | tac > t; mv t ~/.bash_history
6
Lri

Chcete-li jedinečně zaznamenat každý nový příkaz, je složité. Nejprve je třeba přidat do ~/.profile Nebo podobně:

HISTCONTROL=erasedups
Prompt_COMMAND='history -w'

Pak je třeba přidat do ~/.bash_logout:

history -a
history -w
0
Steven Penny