it-swarm-id.com

Bash histori: "ignoredups" dan "erasedups" mengatur konflik dengan riwayat umum di seluruh sesi

Pertama-tama, ini bukan duplikat utas yang ada di SE. Saya telah membaca dua utas ini ( 1 , 2 ) tentang sejarah bash yang lebih baik, tetapi tidak ada jawaban yang berfungsi - - Saya menggunakan Fedora 15.

Saya menambahkan yang berikut ke .bashrc file di direktori pengguna (/ home/aahan /), dan tidak berfungsi. Adakah yang punya petunjuk?

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

Oke inilah yang saya inginkan dengan bash history (prioritas):

  • jangan menyimpan duplikat, hapus yang sudah ada
  • segera bagikan riwayat dengan semua terminal terbuka
  • selalu menambahkan riwayat, bukan menimpanya
  • menyimpan perintah multi-line sebagai satu perintah (yang tidak aktif secara default)
  • apa ukuran Riwayat standar dan ukuran file riwayat?
92
its_me

Ini sebenarnya adalah perilaku yang sangat menarik dan saya akui saya sangat meremehkan pertanyaan di awal. Tapi pertama-tama faktanya:

1. Apa yang berhasil

Fungsionalitas dapat dicapai dalam beberapa cara, meskipun masing-masing bekerja sedikit berbeda. Perhatikan bahwa, dalam setiap kasus, agar riwayat "ditransfer" ke terminal lain (diperbarui), kita harus menekan Enter di terminal, di mana dia ingin mengambil sejarah.

  • pilihan 1:

    shopt -s histappend
    HISTCONTROL=ignoredups
    Prompt_COMMAND="history -a; history -n; $Prompt_COMMAND"
    

    Ini memiliki dua kelemahan:

    1. Saat masuk (membuka terminal), perintah terakhir dari file histori dibaca dua kali ke buffer sejarah terminal saat ini;
    2. Buffer terminal yang berbeda tidak tetap sinkron dengan file histori.
  • pilihan 2:

    HISTCONTROL=ignoredups
    Prompt_COMMAND="history -a; history -c; history -r; $Prompt_COMMAND"
    

    (Ya, tidak perlu untuk shopt -s histappend dan ya, itu harus history -c di tengah-tengah Prompt_COMMAND) Versi ini juga memiliki dua kelemahan penting:

    1. File riwayat harus diinisialisasi. Itu harus mengandung setidaknya satu baris tidak kosong (dapat berupa apa saja).
    2. Perintah history dapat memberikan output yang salah - lihat di bawah.

[Edit] "Dan pemenangnya adalah ..."

  • opsi 3:

    HISTCONTROL=ignoredups:erasedups
    shopt -s histappend
    Prompt_COMMAND="history -n; history -w; history -c; history -r; $Prompt_COMMAND"
    

    Ini sejauh yang didapat. Ini adalah opsi saja untuk membuat erasedups dan riwayat umum berfungsi secara bersamaan. Ini mungkin adalah solusi akhir untuk semua masalah Anda, Aahan.


2. Mengapa opsi 2 tampaknya tidak berfungsi (atau: apa yang sebenarnya tidak berfungsi seperti yang diharapkan)?

Seperti yang saya sebutkan, masing-masing solusi di atas bekerja secara berbeda. Tapi interpretasi yang paling menyesatkan tentang bagaimana pengaturan bekerja berasal dari menganalisis output dari perintah history. Dalam banyak kasus, perintah dapat memberikan false output. Mengapa? Karena dieksekusi sebelum urutan perintah history lain yang terkandung dalam Prompt_COMMAND! Namun, saat menggunakan opsi kedua atau ketiga, seseorang dapat memantau perubahan .bash_history isi (menggunakan watch -n1 "tail -n20 .bash_history" misalnya) dan lihat apa sejarah sebenarnya.

3. Mengapa opsi 3 sangat rumit?

Itu semua terletak pada cara erasedups bekerja. Seperti yang dinyatakan oleh manual bash, "(...) erasedups menyebabkan semua baris sebelumnya yang cocok dengan baris saat ini dihapus dari daftar riwayat sebelum baris tersebut disimpan" . Jadi inilah yang diinginkan OP (dan bukan hanya, seperti yang saya pikirkan sebelumnya, agar tidak ada duplikat yang muncul secara berurutan) . Inilah mengapa masing-masing history -. perintah harus atau tidak bisa di Prompt_COMMAND:

  • history -nmemiliki untuk berada di sana sebelum history -w untuk membaca dari .bash_history perintah yang disimpan dari terminal lain,

  • history -wmemiliki untuk berada di sana untuk menyimpan riwayat ke file dan menghapus duplikat,

  • history -atidak boleh ditempatkan di sana alih-alih history -w, karena tidak memicu penghapusan duplikat,

  • history -c juga diperlukan karena mencegah membuang buffer sejarah setelah setiap perintah,

  • dan akhirnya, history -r is diperlukan untuk mengembalikan buffer sejarah dari file, sehingga akhirnya membuat sejarah dibagikan di seluruh sesi terminal.

126
rozcietrzewiacz

Dalam perintah Prompt Anda, Anda menggunakan -c beralih. Dari man bash:

- c Bersihkan daftar riwayat dengan menghapus semua entri

Untuk membagikan riwayat Anda dengan semua terminal terbuka, Anda dapat menggunakan -n:

- n Baca baris riwayat yang belum dibaca dari file riwayat ke dalam daftar riwayat saat ini. Ini adalah baris yang ditambahkan ke file histori sejak awal sesi bash saat ini.

Ukuran standar juga ada di manual:

HISTSIZE Jumlah perintah yang harus diingat dalam histori perintah (lihat SEJARAH di bawah). Nilai standarnya adalah 500.

Untuk menyimpan perintah multi-line:

Opsi cmdhist Shell, jika diaktifkan, menyebabkan Shell berusaha untuk menyelamatkan setiap baris dari perintah multi-baris dalam entri riwayat yang sama, menambahkan titik koma di mana diperlukan untuk menjaga kebenaran sintaksis. Opsi lithist Shell menyebabkan Shell untuk menyimpan perintah dengan baris baru yang disematkan alih-alih titik koma.

Selain itu, Anda tidak boleh mengawali perintah HIST * dengan export - itu adalah variabel bash-only bukan variabel lingkungan: HISTCONTROL=ignoredups:erasedups Cukup.

8
jasonwryan

Inilah yang saya buat dan saya senang dengan itu sejauh ini ...

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" 

CATATAN:

  • Ya, itu rumit ... tetapi, ia menghapus semua duplikat dan tetap mempertahankan kronologi di dalam setiap terminal!
  • HISTIGNORE saya mengabaikan semua perintah yang tidak memiliki argumen. Ini mungkin tidak diinginkan oleh beberapa orang dan dapat ditinggalkan.
8
user41176

Gunakan ini sebagai gantinya:

HISTCONTROL=ignoreboth
1
verndog

Ini tidak berfungsi, karena Anda lupa tentang:

 -n   read all history lines not already read from the history file
      and append them to the history list

Tapi sepertinya history -n baru buggy saat export HISTCONTROL=ignoreboth:erasedups berlaku.

Mari kita bereksperimen:

$ Prompt_COMMAND=
$ export HISTCONTROL=ignoreboth:erasedups
$ export HISTFILE=~/.bash_myhistory
$ HISTIGNORE='history:history -w'
$ history -c
$ history -w

Di sini kita menghidupkan dups menghapus, beralih histori ke file kustom, menghapus histori. Setelah semua perintah selesai, kami memiliki file riwayat kosong dan satu perintah di riwayat saat ini.

$ history
$ cat ~/.bash_myhistory
$ history
$ 1  [2019-06-17 14:57:19] cat ~/.bash_myhistory

Buka terminal kedua dan jalankan enam perintah itu juga. Setelah itu:

$ 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"

Sekarang riwayat Anda saat ini memiliki dua perintah dan file riwayat memiliki:

#1560772821
echo "X"
#1560772823
echo "Y"

Kembali ke terminal pertama:

$ history -n
$ history
1  [2019-06-17 14:57:19] cat ~/.bash_myhistory 
2  [2019-06-17 15:03:12] history -n

Hah ... tidak ada perintah echo yang dibaca. Beralih lagi ke terminal kedua dan:

$ echo "Z"
$ history -w

Sekarang file histori adalah:

#1560772821
echo "X"
#1560772823
echo "Y"
#1560773057
echo "Z"

Beralih ke terminal pertama lagi:

$ history -n
$ history
  1  [2019-06-17 14:57:19] cat ~/.bash_myhistory 
  2  [2019-06-17 15:03:12] history -n
echo "Z"

Anda dapat melihat bahwa echo "Z" perintah digabung menjadi history -n.

Lain bug adalah karena perintah dibaca dari sejarah dengan nomor perintah dan bukan oleh waktu perintah, saya pikir. Saya mengharapkan perintah echo lainnya muncul di histori

0
Eugen Konkov

Saya pergi dengan kombinasi jawaban di sini:

  • Saya ingin riwayat saya digabungkan pada akhirnya, jadi saya menggunakan fungsi trap.
  • Saya juga ingin file riwayat saya dipisahkan oleh host jadi saya mengubah HISTFILE untuk menunjuk ke direktori dan menamai file tergantung pada nama host.
  • Saya menambahkan opsi abaikan sehingga saya dapat mengetikkan kata sandi teks yang jelas dan tidak membuatnya muncul di riwayat, mis .: $ ./.secretfunction -user myuser -password mypassword Tidak akan disimpan karena dimulai dengan spasi.
  • Saya menambahkan history* Dan exit ke HISTIGNORE hanya untuk menjaga perintah-perintah itu termasuk riwayat masa lalu seperti history | grep awesomecommand Di luar sana karena saya biasanya tidak menginginkannya. Anda dapat menambahkan yang lain seperti: logout, fg, bg, dll.
  • Saya kemudian memasukkan semuanya ke dalam file ~/.bash_aliases saya sehingga tidak bertentangan dengan peningkatan seperti yang kadang-kadang terjadi.
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"

Grep ~/for Prompt_COMMAND Anda untuk memastikan Anda belum memodifikasinya dengan histori -a. Saya juga menambahkan format TIME/DATE HISTTIMEFORMAT="%x %r %Z " Saya suka tetapi tidak termasuk dalam blok di atas karena itu sensitif terhadap lokal.

0
Marlon

erasedups tidak memangkas (seperti chomp dalam beberapa bahasa) ruang utama dan tambahan. Ini adalah bug. Juga terhapus tidak menghapus semua entri sebelumnya.

0

Menggunakan kombinasi opsi @ rozcietrzewiacz 3 dengan trap keluar akan memungkinkan terminal yang mempertahankan sesi sejarah independen mereka sendiri yang konvergen saat ditutup. Bahkan tampaknya berfungsi baik dengan beberapa sesi di berbagai mesin yang berbagi direktori home jarak jauh.

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"
  • Fungsi historymerge memuat baris di luar sesi dari file histori, menggabungkannya dengan histori sesi, menulis file histori baru dengan deduplikasi (sehingga meremukkan setiap baris duplikat yang ditambahkan sebelumnya), dan memuat ulang sejarah.

  • Menjaga history -a di Prompt meminimalkan potensi kehilangan histori, karena ia memperbarui file histori tanpa deduplikasi pada setiap perintah.

  • Akhirnya, jebakan memicu historymerge pada penutupan sesi untuk file riwayat bersih yang terkini dengan perintah sesi terakhir yang ditutup menggelembung ke akhir file (saya pikir).

Dengan ini, setiap sesi terminal akan memiliki sejarah independennya sendiri mulai dari peluncuran. Saya menemukan bahwa lebih bermanfaat karena saya cenderung memiliki terminal yang berbeda terbuka untuk tugas yang berbeda (sehingga saya ingin mengulangi perintah yang berbeda di masing-masing). Ini juga untungnya lebih sederhana daripada memahami beberapa terminal yang terus-menerus berusaha menyinkronkan kembali dipesan sejarahnya dalam mode terdistribusi (meskipun Anda masih bisa melakukannya dengan sengaja menggunakan fungsi historymerge dengan sesi tertentu atau mereka semua).

Perhatikan bahwa Anda ingin batas ukuran Anda cukup besar untuk menampung panjang riwayat yang diinginkan plus volume garis non-deduplikasi yang dapat ditambahkan oleh semua sesi yang aktif secara bersamaan. 5000 cukup bagi saya sebagian besar berkat penggunaan ekstensif HISTIGNORE untuk memfilter perintah spam bernilai rendah.

0
HonoredMule