Problém se ve skutečnosti scvrkává na odlišné chování přihlašovacích a nepřihlašovacích shellů. Nastavil jsem proměnné, které řídí historii v mém ~/.bahsrc
. Tento soubor se nečte při spuštění přihlašovacího shellu, čtou jej pouze interaktivní, nepřihlašovací shelly (od man bash
):
Když je bash vyvolán jako interaktivní přihlašovací shell nebo jako neinteraktivní shell s
--login
nejprve načte a provede příkazy ze souboru/etc/profile
, pokud tento soubor existuje. Po přečtení tohoto souboru hledá ~/.bash_profile,~/.bash_login
a~/.profile
v tomto pořadí a čte a provádí příkazy od prvního, který existuje a je čitelný.--noprofile
Tato možnost může být použita při spuštění shellu k potlačení tohoto chování.[. . . ]
Když je spuštěn interaktivní shell, který není přihlašovacím shellem, bash čte a provádí příkazy z ~/.bashrc, pokud tento soubor existuje. Tomu lze zabránit použitím volby --norc. Volba --rcfile file přinutí bash číst a provádět příkazy ze souboru namísto ~/.bashrc.
Proto pokaždé, když jsem se přihlásil nebo přešel do tty nebo použil ssh, .history
soubor se zkracoval, protože jsem ho nenastavil na správnou velikost v ~/.profile
také. Nakonec jsem si to uvědomil a jednoduše jsem nastavil proměnné v ~/.profile
kam patří, místo ~/.bashrc
Takže důvod můj ~/.history
byl oříznut, protože jsem nastavil pouze proměnné HISTORY v souboru čteném interaktivními, nepřihlašovacími shelly, a proto pokaždé, když jsem spustil jiný typ shellu, proměnné byly ignorovány a soubor by byl odpovídajícím způsobem oříznut.
Můj návrh je použít jiný soubor jako HISTFILE
, nikoli výchozí ~/.bash_history
.
I když nemám žádné analytické vysvětlení, pokusím se nastínit, co mě vedlo k tomuto návrhu:Pokud používáte bash
jako výchozí (přihlašovací) shell a také použijte X
(což je obojí velmi pravděpodobné) máte spuštěný bash
instance hned po (grafickém) přihlášení:
systemd
...
|-login
| `-bash <<====
| `-slim
| |-X -nolisten tcp vt07 -auth /var/run/slim.auth
| | `-{X}
| `-fluxbox
| `-xterm -bg black -fg white
| `-bash
...
Myslím, že tato instance je přihlašovací shell, takže nečte váš ~/.bashrc
a proto nebude vědět nic o histappend
možnost:
man bash(1) :Když interaktivní shell, který není přihlašovací shell se spustí, bash čte a provádí příkazy z /etc/bash.bashrc a ~/.bashrc, pokud tyto soubory existují. (...)
Dokud tento "rodičovský shell" běží, je vše v pořádku, ale po jeho ukončení (tj. zastavení systému) přepíše ~/.bash_history
(protože to je výchozí hodnota) a zkazí vaši historii nebo ji ořízne na start systému na (opět výchozí) 500 řádků. (Nebo možná obojí...)
Také mě napadá, že nestačí zahrnout konfiguraci historie do ~/.bashrc
, protože by to nemělo být tak neobvyklé nastavení. Nemám pro to vysvětlení.
Pokud jde o váš problém, že "přihlašovací shelly stále vykazují stejné chování", můžete zkusit zahrnout konfiguraci historie také do ~/.bash_profile
:
man bash(1) :Když je bash vyvolán jako interaktivní přihlašovací shell nebo jako neinteraktivní shell s volbou --login, nejprve načte a provede příkazy ze souboru /etc/profile, pokud tento soubor existuje. Po přečtení tohoto souboru hledá ~/.bash_profile, (...)
Bohužel nemohu odeslat odůvodněnější vysvětlení s podrobnostmi z mého vlastního bash
config, protože jsem zsh
chlap...
Protože všechna vaše nastavení jsou v pořádku podle manuálové stránky a protože soubor historie není omezen velikostí (bajty), napadá mě jediné možné vysvětlení. Souvisí to s tím, jak skořápka zemře.
Podle online reference dojde k elegantnímu odchodu (historie uložena) pouze tehdy, když shell obdrží SIGHUP. Nemohu skutečně vysvětlit, jak váš systém šíří signály po restartu, ale mám podezření, že váš shell končí pomocí SIGKILL nebo SIGPWR.
Mohlo by to být proto, že váš WM běží asynchronně (čekejte) a emulátor terminálu vytvořený z WM, kde je bash, dostane signál vynucující ukončení jiný než SIGHUP. Může se také stát, že operační systém rychle posílá „finální zabití“ všem procesům, než se počátečnímu elegantnímu SIGHUPu podaří dostat se do shellu přes X -> WM -> xterm, možná proto, že X nebo WM trvá déle, než se ukončí. trvá to, aby byl operační systém připraven ke spuštění.
Jsem v hlubokých vodách s těmito věcmi, ale myslím, že něco v tomto smyslu způsobuje nevyzpytatelné chování. Tento problém jsem měl již dříve a nejspolehlivější řešení je exit
v bash, kde chcete uchovávat historii.
Všiml jsem si history -a
ve vaší otázce a nenapadá mě, proč by to k zachování historie nestačilo.
Problém můžete vyřešit tak, že zjistíte, co skutečně zabíjí váš bash, a přejdete k tomu, abyste zjistili, odkud signál pochází, a problém tam opravte, nebo jednoduše vyprázdněte historii, když víte, který signál je poslední (za předpokladu, že disky jsou do té doby stále online ):
trap "echo got 1 >/tmp/sig1; exit" SIGHUP
trap "echo got 2 >/tmp/sig2; exit" SIGINT
trap "echo got 15 >/tmp/sig15; exit" SIGTERM
.. and so on...
Přiložený snímek obrazovky ilustruje to, o čem mluvím ve druhém a třetím odstavci. Sekvence je I shell v zleva , zabij levou skořápku zprava a začni historii.
chlape
Při spuštění (...) Soubor pojmenovaný hodnotou HISTFILE je v případě potřeby zkrácen tak, aby neobsahoval více řádků, než je zadaný hodnotou HISTFILESIZE (+ výchozí 500).
Pokud je povolena volba shell histappend (+ zde výchozí), řádky se připojí k souboru historie, jinak se soubor historie přepíše.
online reference
3.7.6 Signály
Když je Bash interaktivní, při absenci jakýchkoliv pastí ignoruje SIGTERM (takže ‚kill 0‘ nezabije interaktivní shell) a SIGINT je zachycen a zpracován (takže zabudované čekání je přerušitelné). Když Bash obdrží SIGINT, vypadne ze všech prováděcích smyček. Ve všech případech Bash ignoruje SIGQUIT. Pokud je aktivní řízení úlohy (viz Řízení úlohy), Bash ignoruje SIGTTIN, SIGTTOU a SIGTSTP.
Nezabudované příkazy spouštěné Bashem mají obslužné rutiny signálu nastavené na hodnoty zděděné shellem od svého rodiče. Když řízení úlohy není účinné, asynchronní příkazy ignorují kromě těchto zděděných obslužných rutin SIGINT a SIGQUIT. Příkazy spuštěné jako výsledek substituce příkazů ignorují řídicí signály úlohy SIGTTIN, SIGTTOU a SIGTSTP generované klávesnicí.
Shell se standardně ukončí po přijetí SIGHUP. Před ukončením interaktivní shell znovu odešle SIGHUP všem úlohám, spuštěným i zastaveným. Zastavené úlohy jsou odeslány SIGCONT, aby bylo zajištěno, že obdrží SIGHUP. Aby shell neposílal signál SIGHUP konkrétní úloze, měl by být odstraněn z tabulky úloh s vestavěným disown (viz Job Control Builtins) nebo označen, aby nepřijímal SIGHUP pomocí disown -h.
Pokud byla možnost huponexit shell nastavena pomocí shopt (viz The Shopt Builtin), Bash odešle SIGHUP všem úlohám, když interaktivní přihlašovací shell skončí.
Pokud Bash čeká na dokončení příkazu a přijme signál, pro který byla past nastavena, past nebude provedena, dokud nebude příkaz dokončen. Když Bash čeká na asynchronní příkaz prostřednictvím vestavěné funkce čekání, příjem signálu, pro který byla nastavena past, způsobí, že se zabudovaná funkce čekání okamžitě vrátí se stavem ukončení větším než 128, ihned po kterém se past vykoná.
demonstrativní snímek obrazovky