Zaktualizuj historię bash na innych terminalach przy wychodzeniu z jednego terminala

15

Wiem, że to pytanie nie jest niejasne, ponieważ zadaje się je tutaj, aktualizuj (i duplikuj tutaj).

To, co próbuję osiągnąć, jest nieco inne. Nie podoba mi się pomysł, aby mój monit ponownie zapisywał plik przy każdym lswpisaniu ( history -a; history -c; history -r).

Chciałbym zaktualizować plik przy wyjściu. To proste (właściwie domyślne), ale musisz dołączyć zamiast przepisywać:

shopt -s histappend

Teraz, kiedy terminal jest zamknięty, chciałbym, aby wszyscy inni, którzy pozostają otwarci, byli świadomi aktualizacji.

Wolę to robić bez sprawdzania za $PS1każdym razem, commandgdy piszę. Myślę, że lepiej byłoby uchwycić jakiś sygnał. Jak byś to zrobił? Jeśli nie jest to możliwe, może proste cronjob?

Jak rozwiązać tę zagadkę?

Dr Beco
źródło
1
Zauważ, że zsh robi to od razu po wyjęciu z pudełka (i ma wiele opcji, aby dostosować udostępnianie historii).
Gilles „SO- przestań być zły”
Dzięki @Gilles; Śmieszne, lata z Linuksem i nigdy nie próbowałem niczego innego bash. Może czas sprawdzić coś nowego, dla zabawy.
Dr Beco

Odpowiedzi:

15

Kreatywne i angażujące sygnały, mówisz? DOBRZE:

trap on_exit EXIT
trap on_usr1 USR1

on_exit() {
    history -a
    trap '' USR1
    killall -u "$USER" -USR1 bash
}

on_usr1() {
    history -n
}

Wrzuć to .bashrci idź. Wykorzystuje sygnały, aby kazać każdemu bashprocesowi sprawdzać nowe wpisy historii, gdy inny kończy działanie. To jest okropne, ale naprawdę działa.


Jak to działa?

trapustawia moduł obsługi sygnału dla sygnału systemowego lub jednego z wewnętrznych zdarzeń Basha. EXITWydarzenie jest jakaś sterowana zakończenie skorupy, a USR1to SIGUSR1, bez znaczenia sygnał jesteśmy przywłaszczenia.

Za każdym razem, gdy powłoka wychodzi, my:

  • Dodaj jawnie całą historię do pliku.
  • Wyłącz SIGUSR1moduł obsługi i spraw, aby powłoka zignorowała sygnał.
  • Wyślij sygnał do wszystkich uruchomionych bashprocesów od tego samego użytkownika.

Kiedy SIGUSR1przybywa, my:

  • Załaduj wszystkie nowe wpisy z pliku historii do listy historii pamięci w powłoce.

Ze względu na sposób Bash uchwyty sygnałów, nie będzie rzeczywiście się nowych danych historii aż trafisz Enternastępnym razem, więc to nie robi nic lepszego na tym froncie niż oddanie history -nsię PROMPT_COMMAND. Jednak zapisywanie odczytu pliku jest ciągłe, gdy nic się nie wydarzyło, i nie ma zapisu w ogóle, dopóki powłoka nie wyjdzie.


Wciąż jednak pozostaje kilka problemów. Po pierwsze, domyślną odpowiedzią SIGUSR1jest zakończenie powłoki. Wszelkie inne bashprocesy (na przykład uruchamianie skryptów powłoki) zostaną zabite. .bashrcnie jest ładowany przez nieinteraktywne powłoki. Zamiast tego ładowany jest plik nazwany przezBASH_ENV : możesz ustawić tę zmienną w swoim środowisku globalnie, aby wskazywała na plik za pomocą:

trap '' USR1

w nim, aby zignorować sygnał w nich (co rozwiązuje problem).

Wreszcie, mimo że spełnia to zadanie, zamówienie, które otrzymasz, będzie nieco nietypowe. W szczególności fragmenty historii będą powtarzane w różnych kolejności, gdy zostaną załadowane i zapisane osobno. Jest to zasadniczo związane z tym, o co prosisz, ale pamiętaj, że historia strzałek w górę staje się w tym momencie o wiele mniej przydatna. Zastąpienia historii i tym podobne będą jednak udostępniane i będą działać dobrze.

Michael Homer
źródło
Zastanawiam się, czy włączyłeś .bashrcsygnaturę czasową w pliku, a potem pojawił się coś w rodzaju kroniki towarzyszącej i okresowo korzystał z pliku, wysyłając SIGUSR1fragment według własnego opisu , czy możesz odzyskać chronologiczną historię strzałek w górę?
forquare
To fajne rozwiązanie, ale faktem jest, że inne procesy kończą się po USR1. Czy takie zachowanie występuje również w przypadku USR2?
Dr Beco
Dodam drugi komentarz, ponieważ jestem zdumiony. W jaki sposób proces kojarzy TERM z USR1? Czy USR1 nie jest czymś, z czego może korzystać tylko użytkownik? Czy to jakieś linux bug? Dlaczego inny proces łapie USR1? (Wiem, że nie jest to omawiane tutaj, ale może ujawnię to we właściwym miejscu)
Dr Beco
Domyślnym zachowaniem prawie wszystkich sygnałów jest zakończenie; jest określony w POSIX . To nie jest błąd. Bash pozwoli ci określić, że sygnał będzie ignorowany dla wszystkich jego procesów, więc jest to w porządku dla naszych celów.
Michael Homer
Dzięki @MichaelHomer. Czy masz na myśli tę specyfikację, o której BASH_ENVmowa w tej odpowiedzi? A może znasz bardziej standardowy sposób na wyłączenie tego zła?
Dr Beco