it-swarm-eu.dev

Zachovat historii bash ve více oknech terminálu

Stále mám otevřeno více než jeden terminál. Kdekoli od dvou do deseti, dělá různé bity a bob. Nyní řekněme, že restartuji a otevřu další sadu terminálů. Někteří si pamatují určité věci, jiní zapomenou.

Chci historii, která:

  • Pamatuje si vše z každého terminálu
  • Je okamžitě přístupný z každého terminálu (např. Pokud I ls v jednom, přepněte na jiný již spuštěný terminál a poté stiskněte nahoru, zobrazí se ls)
  • Nezapomíná příkaz, pokud jsou v přední části příkazu mezery.

Mohu udělat něco pro to, aby bash fungoval víc?

565
Oli

Přidejte následující do ~/.bashrc

# Avoid duplicates
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
Prompt_COMMAND="${Prompt_COMMAND:+$Prompt_COMMAND$'\n'}history -a; history -c; history -r"
355
Pablo R.

Tohle je všechno moje .bashrc Související s historií:

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"

Testováno s bash 3.2.17 na Mac OS X 10.5, bash 4.1.7 na 10.6.

257
kch

Zde je můj pokus o sdílení historie relací Bash. To umožní sdílení historie mezi bash relacemi tak, aby se počítadlo historie nezměnilo a rozšíření historie jako !number Nebude fungovat (s určitými omezeními).

Používání Bash verze 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 "[email protected]"
}

Prompt_COMMAND=_bash_history_sync

Vysvětlení:

  1. Připojte právě zadaný řádek k $HISTFILE (Výchozí je .bash_history). To způsobí, že $HISTFILE Poroste o jeden řádek.

  2. Nastavení speciální proměnné $HISTFILESIZE Na nějakou hodnotu způsobí, že Bash zkrátí řádky $HISTFILE Tím, že odstraní nejstarší položky, než budou řádky $HISTFILESIZE.

  3. Vymažte historii probíhající relace. Tím se sníží počítadlo historie o částku $HISTSIZE.

  4. Přečtěte si obsah $HISTFILE A vložte je do aktuální spuštěné historie relací. Tím se zvýší počitadlo historie o počet řádků v $HISTFILE. Počet řádků $HISTFILE Nemusí být nutně $HISTFILESIZE.

  5. Funkce history() přepíše vestavěnou historii a ujistí se, že historie je před zobrazením synchronizována. To je nezbytné pro rozšíření historie o číslo (více o tom později).

Další vysvětlení:

  • Krok 1 zajišťuje, že příkaz z aktuální spuštěné relace bude zapsán do souboru globální historie.

  • Krok 4 zajišťuje, že příkazy z ostatních relací se načtou do aktuální historie relací.

  • Protože krok 4 zvýší čítač historie, musíme čítač nějakým způsobem snížit. To se provádí v kroku 3.

  • V kroku 3 se počítadlo historie sníží o $HISTSIZE. V kroku 4 je počítadlo historie zvýšeno o počet řádků v $HISTFILE. V kroku 2 se ujistíme, že počet řádků $HISTFILE Je přesně $HISTSIZE (To znamená, že $HISTFILESIZE Musí být stejný jako $HISTSIZE).

O omezeních rozšíření historie:

Při použití historie rozšíření o číslo, měli byste vždy vyhledat číslo okamžitě před použitím. To znamená, že se mezi vyhledáním čísla a jeho používáním nezobrazí žádný bash Prompt displej. To obvykle znamená žádný vstup a žádné ctrl + c.

Obecně platí, že jakmile máte více než jednu relaci Bash, neexistuje žádná záruka, že si historie rozšíření o číslo uchová svou hodnotu mezi dvěma obrazovkami Bash Prompt. Protože když je proveden Prompt_COMMAND, Historie ze všech ostatních Bash relací je integrována do historie aktuální relace. Pokud má jakákoli jiná bash relace nový příkaz, budou se čísla historie aktuální relace lišit.

Považuji toto omezení za rozumné. Musím číslo vždy vyhledat, protože si nepamatuji libovolná čísla historie.

Obvykle používám rozšíření historie o takové číslo

$ history | grep something #note number
$ !number

Doporučuji použít následující možnosti Bash.

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

Podivné chyby:

Spuštění příkazu historie přenesené na cokoli způsobí, že tento příkaz bude dvakrát uveden v historii. Například:

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

Všechny budou v historii uvedeny dvakrát. Nemám ponětí, proč.

Nápady na zlepšení:

  • Upravte funkci _bash_history_sync(), aby se neprovedla pokaždé. Například by se neměl spustit po CTRL+C Na výzvě. Často používám CTRL+C, Abych zahodil dlouhý příkazový řádek, když se rozhodnu, že nechci tento řádek spustit. Někdy musím použít CTRL+C, Abych zastavil skript dokončení Bash.

  • Příkazy z aktuální relace by měly být vždy nejnovější v historii aktuální relace. To bude mít také vedlejší účinek, že dané číslo historie si uchová svou hodnotu pro záznamy historie z této relace.

123
lesmana

Nejsem si vědom žádného způsobu použití bash. Ale je to jedna z nejpopulárnějších funkcí zsh .
Osobně dávám přednost zsh před bash, takže doporučuji vyzkoušet.

Tady je část mého .zshrc, která se zabývá historií:

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
45
Maciej Piechotka

Chcete-li to provést, musíte do svého ~/.bashrc:

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

Z man bash:

Pokud je povolena možnost Shell histappend Shell (viz popis šoků pod Shell BUILTIN COMMANDS níže), jsou řádky připojeny k souboru historie, jinak bude soubor historie přepsán.

17
Chris Down

Můžete upravit svůj BASH Prompt tak, aby spustil „history -a“ a „history -r“, které Muerr navrhl:

savePS1=$PS1

(v případě, že něco pokazíte, což je téměř zaručeno)

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

(Všimněte si, že se jedná o zpětná zaškrtnutí; na každém řádku se zobrazí historie -a a historie -r. Protože nevytvářejí žádný text, vaše výzva se nezmění.

Jakmile máte proměnnou PS1 nastavenou tak, jak chcete, nastavte ji trvale ve vašem ~/.bashrc souboru.

Chcete-li se během testování vrátit k původní výzvě, proveďte následující kroky:

PS1=$savePS1

Udělal jsem základní testování, abych zajistil, že to funguje, ale nemůžu mluvit o žádných vedlejších účincích spuštěných history -a;history -r na každém řádku.

11
Schof

Pokud potřebujete synchronizační řešení historie bash nebo zsh, které také řeší problém níže, podívejte se na http://ptspts.blogspot.com/2011/03/how-to-automatically-synchronize-Shell.html

Problém je následující: Mám dvě okna Shell A a B. V okně Shell A spustím sleep 9999 A (bez čekání na dokončení spánku) v okně Shell B chci být schopen viz sleep 9999 v historii bash.

Důvod, proč většina jiných řešení tento problém nevyřeší, je ten, že píšou své změny historie do souboru historie pomocí Prompt_COMMAND Nebo PS1, Z nichž obě se provádějí příliš pozdě, pouze po dokončení příkazu sleep 9999.

10
pts

Dobře, tak mi to nakonec naštvalo najít slušné řešení:

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

Co to dělá, je druh sloučení toho, co bylo řečeno v tomto vlákně, kromě toho, že nechápu, proč byste znovu načíst globální historii po každém příkazu. Velmi zřídka se starám o to, co se děje v jiných terminálech, ale vždy spouštím řadu příkazů, řekněme na jednom terminálu:

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

(Zjednodušený příklad)

A v dalším:

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

V žádném případě bych nechtěl sdílet příkaz

9
Yarek T

Můžeš použít history -a připojte k aktuálnímu souboru historii aktuální relace a poté použijte history -r na ostatních terminálech pro čtení histfile.

9
jtimberman

Tady je alternativa, kterou používám. Je to těžkopádné, ale řeší problém, který @axel_c zmínil, kde někdy budete chtít mít v každém terminálu samostatnou instanci historie (jedna pro značku, jedna pro monitorování, druhá pro vim atd.).

Udržuji samostatný připojený soubor historie, který neustále aktualizuji. Na hotkey jsem mapoval následující:

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

Tím se připojí veškerá historie od aktuálního terminálu k souboru s názvem master_history.txt ve vašem domovském adresáři.

Mám také samostatnou klávesovou zkratku pro vyhledávání v hlavním souboru historie:

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

Používám kočku | grep, protože opustí kurzor na konci a vstoupí do mého regexu. Méně ošklivým způsobem, jak toho dosáhnout, by bylo přidat na cestu několik skriptů, aby bylo možné tyto úkoly splnit, ale klávesové zkratky fungují pro mé účely. Také pravidelně stahuji historii dolů od ostatních hostitelů, na kterých jsem pracoval, a připojím tuto historii k mému souboru master_history.txt.

Je vždy hezké rychle vyhledávat a najít ten složitý regex, který jste použili, nebo ten podivný Perl, který jste vymysleli před 7 měsíci.

8
Toby

Můžu nabídnout opravu té poslední: ujistěte se, že proměnná env HISTCONTROL neurčuje "ignorespace" (nebo "igneboth").

Ale cítím tvou bolest při několika souběžných sezeních. Jednoduše se s bashem nezachází.

7
jmanning2k

Tady je moje vylepšení na @ lesmana's answer . Hlavní rozdíl spočívá v tom, že souběžná okna nesdílejí historii. To znamená, že můžete ve svých oknech pokračovat v práci, aniž byste museli do aktuálních oken načíst kontext jiných oken.

Pokud explicitně zadáte 'history', OR, pokud otevřete nové okno, dostanete historii ze všech předchozích oken).

Také používám tato strategie k archivaci všech příkazů, které jsem kdy napsal na mém počítači.

# 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 "[email protected]"
}

export HISTTIMEFORMAT="%y/%m/%d %H:%M:%S   "
Prompt_COMMAND='history 1 >> ${HOME}/.bash_eternal_history'
Prompt_COMMAND=_bash_history_sync;$Prompt_COMMAND
7
rouble

Rozhodl jsem se dát historii do souboru na tty, protože na stejném serveru může pracovat více lidí - oddělení příkazů každé relace usnadňuje audit.

# 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

Historie nyní vypadá takto:

[email protected]:~# test 123
[email protected]:~# test 5451
[email protected]:~# 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

Se soubory vypadají takto:

[email protected]:~# 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
6
Litch

Zde uvedu jeden problém s

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

a

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

Pokud spustíte zdroj ~/.bashrc, $ Prompt_COMMAND bude jako

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

a

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

K tomuto opakování dochází při každém spuštění 'source ~/.bashrc'. Prompt_COMMAND můžete zkontrolovat po každém spuštění 'source ~/.bashrc' spuštěním 'echo $ Prompt_COMMAND'.

Viděli jste, že některé příkazy jsou zjevně rozbité: "history -n history -a". Dobrou zprávou však je, že stále funguje, protože ostatní části stále tvoří platnou posloupnost příkazů (jen vyvolávání některých dodatečných nákladů v důsledku opakovaného provádění některých příkazů. A ne tak čisté.)

Osobně používám následující jednoduchou verzi:

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

který má většinu funkcí, ale žádný takový problém, jak je uvedeno výše.

Dalším bodem, který je třeba učinit, je: , není tam nic magického . Prompt_COMMAND je pouhá proměnná prostého bash prostředí. Příkazy v něm jsou provedeny dříve, než dostanete bash Prompt (znak $). Například váš Prompt_COMMAND je „echo 123“ a ve vašem terminálu spustíte „ls“. Účinek je jako spuštění "ls; echo 123".

$ Prompt_COMMAND="echo 123"

výstup (Stejně jako spuštění 'Prompt_COMMAND = "echo 123"; $ Prompt_COMMAND'):

123

Spusťte následující:

$ echo 3

výstup:

3
123

"history -a" se používá k zápisu příkazů historie do paměti do ~/.bash_history

"history -c" se používá k vymazání příkazů historie v paměti

"history -r" se používá ke čtení příkazů historie z ~/.bash_history do paměti

Viz vysvětlení příkazů historie zde: http://ss64.com/bash/history.html

PS: Jak zdůraznili ostatní uživatelé, export není nutný. Viz: pomocí exportu v .bashrc

5
fstang

Napsal jsem skript pro nastavení souboru historie na relaci nebo úkol, který vychází z následujícího.

        # 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

Není nutné ukládat každý příkaz historie, ale ukládá ty, na kterých mi záleží, a je snazší je získat, pak projít každým příkazem. Moje verze také obsahuje seznam všech souborů historie a umožňuje jim procházet všechny.

Úplný zdroj: https://github.com/simotek/scripts-config/blob/master/hiset.sh

3
simotek

Zde je řešení, které nespojuje historii jednotlivých jednotlivých relací!

V zásadě je třeba ukládat historii každé relace zvlášť a znovu ji vytvářet na každém řádku. Ano, používá více zdrojů, ale není to tak pomalé, jak by to mohlo znít - zpoždění začíná být patrné, pouze pokud máte více než 100 000 záznamů historie.

Zde je základní 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

Úplné řešení viz this Gist , včetně některých záruk a optimalizací výkonu.

3
Jan Warchoł

Protože dávám přednost nekonečné historii, která byla uložena ve vlastním souboru. Tuto konfiguraci vytvářím na základě 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"
2
Eugen Konkov

Toto funguje pro 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
2
Mulki

Dlouho jsem to chtěl, zejména schopnost načíst příkaz, podle kterého byl spuštěn, aby se znovu spustil v novém projektu (nebo najít adresář příkazem). Takže jsem dal tento nástroj dohromady, což kombinuje předchozí řešení pro ukládání globální historie CLI s interaktivním greppingovým nástrojem zvaným percol (mapovaný na C ^ R). Na prvním stroji, který jsem začal používat, je stále úhledný, nyní s> 2letou historií CLI.

Co se týče kláves se šipkami, nepatří sem místní historie CLI, ale umožňuje poměrně snadný přístup k globální historii (kterou můžete také namapovat na něco jiného než C ^ R).

2
Gordon Wells

Zde je úryvek z mého .bashrc a krátká vysvětlení, kdykoli je to potřeba:

# 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 a HISTSIZE jsou osobní preference a můžete je změnit podle svého vkusu.

0
Hopping Bunny