it-swarm-id.com

Pertahankan histori bash di banyak terminal windows

Saya secara konsisten memiliki lebih dari satu terminal terbuka. Di mana saja dari dua hingga sepuluh, melakukan berbagai bit dan bobs. Sekarang katakanlah saya me-restart dan membuka terminal lain. Beberapa mengingat hal-hal tertentu, beberapa lupa.

Saya ingin sejarah yang:

  • Ingat semuanya dari setiap terminal
  • Langsung dapat diakses dari setiap terminal (mis. Jika saya ls dalam satu, beralih ke terminal lain yang sudah berjalan dan kemudian tekan ke atas, ls muncul)
  • Tidak lupa perintah jika ada spasi di depan perintah.

Adakah yang bisa saya lakukan untuk membuat bash bekerja lebih seperti itu?

565
Oli

Tambahkan berikut ini ke ~/.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.

Jadi, ini semua terkait .bashrc Saya yang terkait dengan sejarah:

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"

Diuji dengan bash 3.2.17 pada Mac OS X 10.5, bash 4.1.7 pada 10.6.

257
kch

Ini adalah upaya saya untuk berbagi riwayat sesi Bash. Ini akan memungkinkan pembagian riwayat antara sesi bash sedemikian rupa sehingga penghitung riwayat tidak ikut campur dan ekspansi riwayat seperti !number Akan bekerja (dengan beberapa kendala).

Menggunakan Bash versi 4.1.5 di bawah 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

Penjelasan:

  1. Tambahkan baris yang baru saja dimasukkan ke $HISTFILE (Standarnya adalah .bash_history). Ini akan menyebabkan $HISTFILE Tumbuh satu baris.

  2. Mengatur variabel khusus $HISTFILESIZE Ke beberapa nilai akan menyebabkan Bash memotong $HISTFILE Tidak lebih dari garis $HISTFILESIZE Dengan menghapus entri tertua.

  3. Hapus riwayat sesi lari. Ini akan mengurangi penghitung riwayat dengan jumlah $HISTSIZE.

  4. Baca konten $HISTFILE Dan masukkan ke riwayat sesi berjalan saat ini. ini akan meningkatkan penghitung sejarah dengan jumlah baris dalam $HISTFILE. Perhatikan bahwa jumlah baris $HISTFILE Belum tentu $HISTFILESIZE.

  5. Fungsi history() menimpa riwayat bawaan untuk memastikan bahwa riwayat disinkronkan sebelum ditampilkan. Ini diperlukan untuk ekspansi sejarah dengan angka (lebih lanjut tentang ini nanti).

Penjelasan lebih lanjut:

  • Langkah 1 memastikan bahwa perintah dari sesi berjalan saat ini akan ditulis ke file riwayat global.

  • Langkah 4 memastikan bahwa perintah dari sesi lain dapat dibaca ke riwayat sesi saat ini.

  • Karena langkah 4 akan meningkatkan penghitung sejarah, kita perlu mengurangi penghitung dengan beberapa cara. Ini dilakukan pada langkah 3.

  • Pada langkah 3 penghitung sejarah dikurangi oleh $HISTSIZE. Pada langkah 4 penghitung sejarah dinaikkan oleh jumlah baris dalam $HISTFILE. Pada langkah 2 kami memastikan bahwa jumlah baris $HISTFILE Persis $HISTSIZE (Ini berarti bahwa $HISTFILESIZE Harus sama dengan $HISTSIZE).

Tentang kendala ekspansi sejarah:

Saat menggunakan ekspansi riwayat dengan angka, Anda harus selal mencari nomor segera sebelum menggunakannya. Itu berarti tidak ada bash tampilan Prompt antara mencari nomor dan menggunakannya. Itu biasanya berarti tidak masuk dan tidak ada ctrl + c.

Secara umum, setelah Anda memiliki lebih dari satu sesi Bash, tidak ada jaminan apa pun bahwa ekspansi berdasarkan angka akan mempertahankan nilainya di antara dua tampilan Bash Prompt. Karena ketika Prompt_COMMAND Dijalankan, riwayat dari semua sesi Bash lainnya terintegrasi dalam riwayat sesi saat ini. Jika ada sesi bash lain yang memiliki perintah baru, maka nomor riwayat sesi saat ini akan berbeda.

Saya menemukan batasan ini masuk akal. Lagi pula saya harus mencari nomornya karena saya tidak dapat mengingat angka sejarah yang berubah-ubah.

Biasanya saya menggunakan ekspansi sejarah dengan nomor seperti ini

$ history | grep something #note number
$ !number

Saya sarankan menggunakan opsi Bash berikut.

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

Bug aneh:

Menjalankan perintah histori yang disalurkan ke apa saja akan menghasilkan perintah yang terdaftar dalam histori dua kali. Sebagai contoh:

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

Semua akan terdaftar dalam sejarah dua kali. Saya tidak tahu kenapa.

Gagasan untuk peningkatan:

  • Ubah fungsi _bash_history_sync() sehingga tidak dijalankan setiap waktu. Sebagai contoh, seharusnya tidak dieksekusi setelah CTRL+C Pada Prompt. Saya sering menggunakan CTRL+C Untuk membuang baris perintah yang panjang ketika saya memutuskan bahwa saya tidak ingin mengeksekusi baris itu. Kadang-kadang saya harus menggunakan CTRL+C Untuk menghentikan skrip penyelesaian Bash.

  • Perintah dari sesi saat ini harus selalu yang terbaru dalam sejarah sesi saat ini. Ini juga akan memiliki efek samping bahwa nomor sejarah yang diberikan menyimpan nilainya untuk entri riwayat dari sesi ini.

123
lesmana

Saya tidak mengetahui cara apa pun menggunakan bash. Tapi itu salah satu fitur paling populer zsh .
Secara pribadi saya lebih suka zsh lebih dari bash jadi saya sarankan untuk mencobanya.

Inilah bagian dari .zshrc Saya yang berkaitan dengan sejarah:

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

Untuk melakukan ini, Anda harus menambahkan dua baris ke ~/.bashrc Anda:

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

Dari man bash:

Jika opsi histappend Shell diaktifkan (lihat deskripsi shopt di bawah Shell BUILTIN COMMANDS di bawah), baris ditambahkan ke file histori, jika tidak, file histori dituliskan secara berlebihan.

17
Chris Down

Anda dapat mengedit BASH Prompt Anda untuk menjalankan "history -a" dan "history -r" yang disarankan Muerr:

savePS1=$PS1

(Jika Anda mengacaukan sesuatu, yang hampir dijamin)

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

(perhatikan bahwa ini adalah tick-back; mereka akan menjalankan history -a dan history -r pada setiap Prompt. Karena mereka tidak menampilkan teks apa pun, Prompt Anda tidak akan berubah.

Setelah Anda mengatur variabel PS1 seperti yang Anda inginkan, atur secara permanen di file ~/.bashrc Anda.

Jika Anda ingin kembali ke Prompt asli saat menguji, lakukan:

PS1=$savePS1

Saya telah melakukan pengujian dasar tentang ini untuk memastikan bahwa itu berfungsi, tetapi tidak dapat berbicara dengan efek samping dari menjalankan history -a;history -r pada setiap Prompt.

11
Schof

Jika Anda memerlukan solusi sinkronisasi sinkronisasi bash atau zsh yang juga menyelesaikan masalah di bawah ini, maka lihat di http://ptspts.blogspot.com/2011/03/how-to-automatically-synchronize-Shell.html

Masalahnya adalah sebagai berikut: Saya memiliki dua jendela Shell A dan B. Di jendela Shell A, saya menjalankan sleep 9999, dan (tanpa menunggu tidur selesai) di jendela Shell B, saya ingin dapat melihat sleep 9999 dalam riwayat bash.

Alasan mengapa sebagian besar solusi lain di sini tidak akan menyelesaikan masalah ini adalah karena mereka menulis perubahan riwayat mereka ke file riwayat menggunakan Prompt_COMMAND atau PS1, keduanya terlambat dieksekusi, hanya setelah sleep 9999 perintah telah selesai.

10
pts

Benar, Jadi akhirnya ini mengganggu saya untuk menemukan solusi yang layak:

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

Apa yang dilakukan adalah penggabungan dari apa yang dikatakan di utas ini, kecuali bahwa saya tidak mengerti mengapa Anda memuat ulang sejarah global setelah setiap perintah. Saya sangat jarang peduli dengan apa yang terjadi di terminal lain, tetapi saya selalu menjalankan serangkaian perintah, misalnya di satu terminal:

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

(Contoh sederhana)

Dan di tempat lain:

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

Tidak mungkin saya ingin perintah itu dibagikan

9
Yarek T

Kamu bisa menggunakan history -a untuk menambahkan riwayat sesi saat ini ke histfile, lalu gunakan history -r di terminal lain untuk membaca histfile.

9
jtimberman

Inilah alternatif yang saya gunakan. Ini rumit tetapi ini mengatasi masalah yang @axel_c sebutkan di mana kadang-kadang Anda mungkin ingin memiliki instance history terpisah di setiap terminal (satu untuk make, satu untuk pemantauan, satu untuk vim, dll).

Saya menyimpan file riwayat tambahan terpisah yang terus saya perbarui. Saya memetakan berikut ini ke hotkey:

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

Ini menambahkan semua riwayat dari terminal saat ini ke file yang disebut master_history.txt di direktori home Anda.

Saya juga memiliki hotkey terpisah untuk mencari melalui file master history:

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

Saya menggunakan cat | grep karena ia meninggalkan kursor di akhir untuk memasukkan regex saya. Cara yang kurang jelek untuk melakukan ini adalah dengan menambahkan beberapa skrip ke jalur Anda untuk menyelesaikan tugas-tugas ini, tetapi hotkey berfungsi untuk tujuan saya. Saya juga secara berkala akan menarik riwayat dari host lain yang telah saya kerjakan dan menambahkan riwayat itu ke file master_history.txt saya.

Itu selalu menyenangkan untuk dapat dengan cepat mencari dan menemukan regex rumit yang Anda gunakan atau Perl satu-liner aneh yang Anda buat 7 bulan lalu.

8
Toby

Saya dapat menawarkan perbaikan untuk yang terakhir: pastikan variabel env HISTCONTROL tidak menentukan "ignorespace" (atau "ignoreboth").

Tapi saya merasakan sakit Anda dengan beberapa sesi bersamaan. Ini tidak ditangani dengan baik di bash.

7
jmanning2k

Ini adalah peningkatan saya ke @ lesmana's answer . Perbedaan utama adalah bahwa windows bersamaan tidak membagikan sejarah. Ini berarti Anda dapat tetap bekerja di windows Anda, tanpa konteks dari jendela lain yang dimuat ke windows Anda saat ini.

Jika Anda secara eksplisit mengetik 'history', OR jika Anda membuka jendela baru maka Anda mendapatkan riwayat dari semua jendela sebelumnya.

Juga, saya menggunakan strategi ini untuk mengarsipkan setiap perintah yang pernah diketik di mesin saya.

# 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

Saya memilih untuk memasukkan histori dalam file-per-tty, karena banyak orang dapat bekerja pada server yang sama - memisahkan setiap perintah sesi membuatnya lebih mudah untuk diaudit.

# 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

Sejarah sekarang terlihat seperti:

[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

Dengan file yang terlihat seperti:

[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

Di sini saya akan menunjukkan satu masalah dengan

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

dan

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

Jika Anda menjalankan source ~/.bashrc, $ Prompt_COMMAND akan menjadi seperti

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

dan

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

Pengulangan ini terjadi setiap kali Anda menjalankan 'source ~/.bashrc'. Anda dapat memeriksa Prompt_COMMAND setelah setiap kali Anda menjalankan 'source ~/.bashrc' dengan menjalankan 'echo $ Prompt_COMMAND'.

Anda bisa melihat beberapa perintah tampaknya rusak: "history -n history -a". Tetapi kabar baiknya adalah masih berfungsi, karena bagian lain masih membentuk urutan perintah yang valid (Hanya melibatkan beberapa biaya tambahan karena mengeksekusi beberapa perintah berulang-ulang. Dan tidak begitu bersih.)

Secara pribadi saya menggunakan versi sederhana berikut:

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

yang memiliki sebagian besar fungsi sementara tidak ada masalah seperti yang disebutkan di atas.

Hal lain yang perlu diperhatikan adalah: benar-benar tidak ada keajaiban . Prompt_COMMAND hanyalah variabel lingkungan bash biasa. Perintah di dalamnya dieksekusi sebelum Anda mendapatkan bash Prompt (tanda $). Misalnya, Prompt_COMMAND Anda adalah "echo 123", dan Anda menjalankan "ls" di terminal Anda. Efeknya seperti menjalankan "ls; echo 123".

$ Prompt_COMMAND="echo 123"

output (Sama seperti menjalankan 'Prompt_COMMAND = "echo 123"; $ Prompt_COMMAND'):

123

Jalankan yang berikut ini:

$ echo 3

keluaran:

3
123

"history -a" digunakan untuk menulis perintah history dalam memori ke ~/.bash_history

"history -c" digunakan untuk menghapus perintah history dalam memori

"history -r" digunakan untuk membaca perintah history dari ~/.bash_history ke memori

Lihat penjelasan perintah sejarah di sini: http://ss64.com/bash/history.html

PS: Seperti yang ditunjukkan oleh pengguna lain, ekspor tidak perlu. Lihat: menggunakan ekspor dalam .bashrc

5
fstang

Saya telah menulis skrip untuk mengatur file riwayat per sesi atau tugas berdasarkan dari berikut ini.

        # 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

Tidak perlu menyimpan setiap perintah sejarah tetapi menyimpan yang saya pedulikan dan lebih mudah untuk mengambilnya kemudian melalui setiap perintah. Versi saya juga mencantumkan semua file riwayat dan menyediakan kemampuan untuk mencari semua file itu.

Sumber lengkap: https://github.com/simotek/scripts-config/blob/master/hiset.sh

3
simotek

Inilah solusi yang tidak mencampur sejarah dari sesi individu!

Pada dasarnya seseorang harus menyimpan sejarah setiap sesi secara terpisah dan membuatnya kembali di setiap Prompt. Ya, ia menggunakan lebih banyak sumber daya, tetapi tidak selambat kedengarannya - penundaan mulai terlihat hanya jika Anda memiliki lebih dari 100.000 entri riwayat.

Inilah logika intinya:

# 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

Lihat Intisari ini untuk solusi lengkap, termasuk beberapa pengamanan dan optimalisasi kinerja.

3
Jan Warchoł

Karena saya lebih suka riwayat tak terbatas yang disimpan dalam file khusus. Saya membuat konfigurasi ini berdasarkan 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

Ini berfungsi untuk 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

Saya sudah lama menginginkan ini, terutama kemampuan untuk mengambil perintah di mana ia dijalankan untuk mengeksekusi kembali dalam proyek baru (atau menemukan direktori dengan perintah). Jadi saya menempatkan alat ini bersama-sama, yang menggabungkan solusi sebelumnya untuk menyimpan sejarah CLI global dengan alat grepping interaktif yang disebut percol (dipetakan ke C ^ R). Masih licin pada mesin pertama yang saya mulai menggunakannya, sekarang dengan riwayat CLI> 2 tahun.

Itu tidak mengacaukan sejarah CLI lokal sejauh menyangkut tombol panah, tetapi memungkinkan Anda mengakses sejarah global dengan cukup mudah (yang Anda juga dapat memetakan ke sesuatu selain C ^ R)

2
Gordon Wells

Berikut ini cuplikan dari .bashrc saya dan penjelasan singkat di mana pun dibutuhkan:

# 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 dan HISTSIZE adalah preferensi pribadi dan Anda dapat mengubahnya sesuai selera Anda.

0
Hopping Bunny