Bảo tồn lịch sử bash trong nhiều cửa sổ đầu cuối


526

Tôi luôn có nhiều thiết bị đầu cuối mở. Bất cứ nơi nào từ hai đến mười, làm nhiều bit và bobs. Bây giờ hãy nói rằng tôi khởi động lại và mở ra một bộ thiết bị đầu cuối khác. Một số nhớ những điều nhất định, một số quên.

Tôi muốn một lịch sử:

  • Nhớ mọi thứ từ mọi thiết bị đầu cuối
  • Có thể truy cập ngay lập tức từ mọi thiết bị đầu cuối (ví dụ: nếu tôi lstrong một, chuyển sang thiết bị đầu cuối khác đang chạy và sau đó nhấn lên, lshiển thị)
  • Không quên lệnh nếu có khoảng trắng ở phía trước lệnh.

Bất cứ điều gì tôi có thể làm để làm cho bash hoạt động như vậy?


57
Tôi có thể thấy lợi thế của điều đó, nhưng cá nhân tôi sẽ ghét điều đó trong vỏ bọc của mình. Tôi thường giữ 3 hoặc 4 tab mở trong thiết bị đầu cuối của mình để sử dụng rất cụ thể: một để chạy 'make', một với vi, một để chạy công cụ, v.v. Vì vậy, khi tôi biên dịch, tôi chuyển đến tab 1, nhấn và 'tạo 'đi lên, và như vậy. Điều này là cực kỳ năng suất với tôi. Vì vậy, nếu đột nhiên tôi vào tab 'make' của mình và đánh lên và một số lệnh grep ngẫu nhiên xuất hiện, tôi sẽ thực sự bực mình! Chỉ là một ghi chú cá nhân
axel_c

4
@axel_c Điều đó đủ đúng. Tôi không thể nghĩ ra một cách thông minh để làm điều đó khi các thiết bị đầu cuối hiện tại chỉ nhìn thấy lịch sử của riêng họ nhưng những cái mới nhìn thấy một danh sách các lệnh chính xác theo thời gian.
Oli

8
@Oli đã viết, "Tôi không thể nghĩ ra một cách thông minh để làm điều đó khi các thiết bị đầu cuối hiện tại chỉ nhìn thấy lịch sử của riêng họ nhưng những người mới thấy một danh sách các lệnh chính xác theo thời gian." Làm thế nào về (chưa được thử) : export PROMPT_COMMAND="history -a; $PROMPT_COMMAND". Các shell hiện có sẽ thêm từng lệnh vào tệp lịch sử để xem các shell mới, nhưng chỉ hiển thị lịch sử của riêng chúng.
Chris Trang

2
Bạn có muốn tất cả lịch sử được lưu trữ riêng biệt hoặc tất cả được hợp nhất vào một tệp lịch sử không?
kbyrd

3
Câu trả lời ngắn gọn là: nó không dành cho các nhà phát triển bash. Các giải pháp dựa trên việc xả nước sau đó đọc lại lịch sử có thể có tác dụng, nhưng hãy cẩn thận với Shlemiel The Họa sĩ . Nói một cách dễ hiểu: lượng công việc xử lý giữa mỗi lệnh tỷ lệ thuận với kích thước lịch sử.
Stéphane Gourichon

Câu trả lời:


329

Thêm phần sau vào ~ / .bashrc

# Avoid duplicates
export 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
export PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"

20
Vấn đề với giải pháp PROMPT_COMMAND này là các số cho mỗi mục lịch sử thay đổi sau mỗi lệnh :(. Ví dụ: nếu bạn nhập lịch sử và 1) ls 2) rm, thì bạn làm! 1 để lặp lại 1, số lịch sử có thể thay đổi và có thể chạy lệnh rm ...
Chris Kimpton

2
Khi tôi thực hiện việc này, các thiết bị đầu cuối đã mở khác không có lệnh được nhập cuối cùng khi tôi nhấn 'Lên' cho đến khi tôi phát lệnh trong thiết bị đầu cuối đó - điều này có được mong đợi không? Nếu vậy, có cách nào để thực sự sửa đổi lịch sử của các thiết bị đầu cuối khác ngay lập tức không?
Suan

7
@Suan, điều này có vẻ đúng với tôi dựa trên các lệnh. Tôi thấy rằng chúng ta có thể ban hành lệnh null (chỉ cần nhấn phím enter) để lấy lịch sử cập nhật.
hiền nhân

3
Trên thực tế history -a(...) không kích hoạt việc xóa các bản sao theo câu trả lời này cho câu hỏi Lịch sử Bash: đã bỏ qua các trò chơi bị xóa và các trò chơi xóa bỏ xung đột với một lịch sử chung . Câu trả lời này cũng đưa ra chuỗi các history -<option>lệnh hoạt động với HISTCONTROL=ignoredups:erasedupscài đặt.
Piotr Dobrogost

23
Không có lý do nào cho exportcác biến HISTCONTROLPROMPT_COMMANDbiến: bạn đang xác định chúng .bashrcđể chúng sẽ được xác định trong mọi shell (ngay cả trong các không tương tác, điều này cũng gây lãng phí).
heo

248

Vì vậy, đây là tất cả những .bashrcđiều liên quan đến lịch sử của tôi :

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"

Đã thử nghiệm với bash 3.2.17 trên Mac OS X 10.5, bash 4.1.7 trên 10.6.


3
Hmm .. Điều này sẽ giết chết khả năng sử dụng $! 34, vì các số lệnh thay đổi mọi dấu nhắc. Có cách giải quyết @Davide @Schof @kch không?

5
Sử dụng điều này để có được lịch sử vô tận: bash lịch sử vĩnh cửu . TUY NHIÊN, đây là mã miễn phí ở trên, vì nó sẽ không được tải lại tự động.

7
FYI Không có giải pháp nào được đề cập ở đây có thể giải quyết vấn đề sau. Tôi có hai cửa sổ shell A và B. Trong cửa sổ shell A, tôi chạy sleep 9999và (không đợi giấc ngủ kết thúc) trong cửa sổ shell B, tôi muốn có thể nhìn thấy sleep 9999trong lịch sử bash.
pts

1
@pts Tôi cũng đang nhắm đến hành vi sống, nhưng sau đó tôi nhận ra rằng sẽ thuận tiện hơn khi có lịch sử cụ thể của thiết bị đầu cuối, giúp làm việc trên những thứ khác nhau trong các thiết bị đầu cuối khác nhau dễ dàng hơn. Tôi thấy điều này rất hữu ích: stackoverflow.com/questions/338285/#answer-7449399 Dựa vào đó, tôi tự tạo cho mình một bí danh gọi là hreflàm mới lịch sử của thiết bị đầu cuối hiện tại của tôi ngay lập tức và xóa tệp lịch sử trong quy trình. Bất cứ khi nào tôi mở một thiết bị đầu cuối mới, việc dọn dẹp / đồng bộ hóa đó được thực thi trong tệp bashrc của tôi để thiết bị đầu cuối mới có lịch sử mới nhất. Tôi đang sử dụng cùng vớihistory -a
trusktr

6
Không có lý do nào cho exportcác biến: bạn đang xác định chúng .bashrcđể chúng sẽ được xác định trong mọi shell (ngay cả trong các biến không tương tác, cũng gây lãng phí)
dolmen

118

Đây là nỗ lực của tôi tại chia sẻ lịch sử phiên Bash. Điều này sẽ cho phép chia sẻ lịch sử giữa các phiên bash theo cách mà bộ đếm lịch sử không bị lẫn lộn và mở rộng lịch sử như !numbersẽ hoạt động (với một số ràng buộc).

Sử dụng Bash phiên bản 4.1.5 trong 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 "$@"
}

PROMPT_COMMAND=_bash_history_sync

Giải trình:

  1. Nối dòng vừa nhập vào $HISTFILE(mặc định là .bash_history). Điều này sẽ gây ra $HISTFILEtăng trưởng bởi một dòng.

  2. Đặt biến đặc biệt $HISTFILESIZEthành một số giá trị sẽ khiến Bash cắt ngắn $HISTFILEkhông dài hơn $HISTFILESIZEcác dòng bằng cách xóa các mục cũ nhất.

  3. Xóa lịch sử của phiên chạy. Điều này sẽ làm giảm bộ đếm lịch sử theo số lượng $HISTSIZE.

  4. Đọc nội dung $HISTFILEvà chèn chúng vào lịch sử phiên chạy hiện tại. điều này sẽ nâng bộ đếm lịch sử theo số lượng dòng trong $HISTFILE. Lưu ý rằng số lượng dòng $HISTFILEkhông nhất thiết phải $HISTFILESIZE.

  5. Các history()chức năng ghi đè lịch sử dựng sẵn để đảm bảo rằng lịch sử được đồng bộ hóa trước khi nó được hiển thị. Điều này là cần thiết cho việc mở rộng lịch sử theo số (sẽ nói thêm về điều này sau).

Giải thích thêm:

  • Bước 1 đảm bảo rằng lệnh từ phiên chạy hiện tại sẽ được ghi vào tệp lịch sử toàn cầu.

  • Bước 4 đảm bảo rằng các lệnh từ các phiên khác được đọc vào lịch sử phiên hiện tại.

  • Bởi vì bước 4 sẽ nâng bộ đếm lịch sử, chúng ta cần giảm bộ đếm theo một cách nào đó. Điều này được thực hiện trong bước 3.

  • Trong bước 3, bộ đếm lịch sử được giảm bởi $HISTSIZE. Trong bước 4, bộ đếm lịch sử được nâng lên bởi số lượng dòng trong $HISTFILE. Trong bước 2, chúng tôi đảm bảo rằng số dòng $HISTFILElà chính xác $HISTSIZE(điều này có nghĩa là $HISTFILESIZEphải giống như $HISTSIZE).

Về những hạn chế của việc mở rộng lịch sử:

Khi sử dụng mở rộng lịch sử theo số, bạn phải luôn tra cứu số ngay trước khi sử dụng. Điều đó có nghĩa là không hiển thị dấu nhắc bash giữa tìm kiếm số và sử dụng nó. Điều đó thường có nghĩa là không nhập và không ctrl + c.

Nói chung, một khi bạn có nhiều hơn một phiên Bash, không có gì đảm bảo rằng việc mở rộng lịch sử theo số sẽ giữ nguyên giá trị của nó giữa hai màn hình nhắc Bash. Bởi vì khi PROMPT_COMMANDđược thực thi, lịch sử từ tất cả các phiên Bash khác được tích hợp trong lịch sử của phiên hiện tại. Nếu bất kỳ phiên bash nào khác có lệnh mới thì số lịch sử của phiên hiện tại sẽ khác.

Tôi thấy hạn chế này hợp lý. Dù sao tôi cũng phải tìm số lên vì tôi không thể nhớ số lịch sử tùy ý.

Thông thường tôi sử dụng mở rộng lịch sử theo số như thế này

$ history | grep something #note number
$ !number

Tôi khuyên bạn nên sử dụng các tùy chọn Bash sau.

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

Lỗi lạ:

Chạy lệnh lịch sử được dẫn đến bất cứ điều gì sẽ dẫn đến lệnh đó được liệt kê trong lịch sử hai lần. Ví dụ:

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

Tất cả sẽ được liệt kê trong lịch sử hai lần. Tôi không biết tại sao.

Ý tưởng để cải tiến:

  • Sửa đổi chức năng _bash_history_sync()để nó không thực hiện mọi lúc. Ví dụ, nó không nên thực hiện sau một CTRL+Cdấu nhắc. Tôi thường sử dụng CTRL+Cđể loại bỏ một dòng lệnh dài khi tôi quyết định rằng tôi không muốn thực thi dòng đó. Đôi khi tôi phải sử dụng CTRL+Cđể dừng một kịch bản hoàn thành Bash.

  • Các lệnh từ phiên hiện tại phải luôn là lần gần đây nhất trong lịch sử của phiên hiện tại. Điều này cũng sẽ có tác dụng phụ là một số lịch sử nhất định sẽ giữ giá trị của nó cho các mục lịch sử từ phiên này.


1
Tại sao không "history -n" (tải lại các dòng chưa được tải) thay vì "history -c; history -r"?
Graham

@Graham: Tôi không muốn sử dụng history -nvì nó làm rối tung quầy lịch sử. Ngoài ra, tôi thấy history -nlà quá không đáng tin cậy.
lesmana

1
Một nhược điểm: Các lệnh có chuỗi nhiều dòng thường vẫn được giữ nguyên trong phiên hiện tại. Với thủ thuật này, chúng được chia thành các dòng riêng lẻ ngay lập tức. Sử dụng -n cho -c -r không giúp ích gì cả, cũng không phải là cmdhist hay lithist. Tôi không nghĩ rằng có một cách giải quyết tại thời điểm này.
Jo Liss

24
Sau khi thử điều này một chút, tôi thực sự thấy rằng chỉ chạy history -a, không -c-r, là khả năng sử dụng tốt hơn (mặc dù đó không phải là câu hỏi được hỏi). Nó có nghĩa là các lệnh bạn chạy có sẵn ngay lập tức trong các shell mới ngay cả trước khi thoát khỏi shell hiện tại, nhưng không phải trong các shell đang chạy đồng thời. Bằng cách này, Arrow-Up vẫn luôn chọn các lệnh chạy cuối cùng của phiên hiện tại , điều mà tôi thấy ít gây nhầm lẫn hơn.
Jo Liss

câu trả lời cực kỳ tốt, công việc này đáng tin cậy không giống như "lịch sử -a; lịch sử -n" phổ biến hơn
RichVel

42

Tôi không biết cách sử dụng bash. Nhưng đó là một trong những tính năng phổ biến nhất của zsh.
Cá nhân tôi thích zshhơn bashvì vậy tôi khuyên bạn nên thử nó.

Đây là một phần của tôi .zshrcliên quan đến lịch sử:

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


16

Để làm điều này, bạn sẽ cần thêm hai dòng vào ~/.bashrc:

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

Từ man bash:

Nếu tùy chọn shell histappend được bật (xem mô tả về shopt trong SHELL BUILTIN THÔNG TIN bên dưới), các dòng được gắn vào tệp lịch sử, nếu không thì tệp lịch sử bị ghi đè.


10

Bạn có thể chỉnh sửa lời nhắc BASH của mình để chạy "history -a" và "history -r" mà Muerr đề xuất:

savePS1=$PS1

(trong trường hợp bạn làm hỏng thứ gì đó, gần như được đảm bảo)

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

(lưu ý rằng đây là các dấu kiểm ngược; chúng sẽ chạy lịch sử -a và lịch sử -r trên mỗi dấu nhắc. Vì chúng không xuất bất kỳ văn bản nào, lời nhắc của bạn sẽ không thay đổi.

Khi bạn đã có biến PS1 của mình được thiết lập theo cách bạn muốn, hãy đặt biến đó vĩnh viễn trong tệp ~ / .bashrc của bạn.

Nếu bạn muốn quay lại dấu nhắc ban đầu của mình trong khi thử nghiệm, hãy làm:

PS1=$savePS1

Tôi đã thực hiện thử nghiệm cơ bản về điều này để đảm bảo rằng nó hoạt động, nhưng không thể nói với bất kỳ tác dụng phụ nào khi chạy history -a;history -rtrên mọi dấu nhắc.


2
giải pháp của kch hoạt động tốt hơn của tôi. Bây giờ tôi đang sử dụng giải pháp của anh ấy trong .bashrc.

9

Nếu bạn cần một giải pháp đồng bộ hóa lịch sử bash hoặc zsh cũng giải quyết được vấn đề bên dưới, thì hãy xem tại http://ptspts.blogspot.com/2011/03/how-to-automatically-synyncize-shell.html

Vấn đề là như sau: Tôi có hai cửa sổ shell A và B. Trong cửa sổ shell A, tôi chạy sleep 9999và (không đợi giấc ngủ kết thúc) trong cửa sổ shell B, tôi muốn có thể nhìn thấy sleep 9999trong lịch sử bash.

Lý do tại sao hầu hết các giải pháp khác ở đây sẽ không giải quyết được vấn đề này là vì họ đang viết các thay đổi lịch sử của họ vào tệp lịch sử bằng cách sử dụng PROMPT_COMMANDhoặc PS1cả hai đều thực thi quá muộn, chỉ sau khi sleep 9999lệnh kết thúc.


1
Đây là một giải pháp tốt, nhưng tôi đã nhận được một vài câu hỏi. 1. Tôi có thể sử dụng tệp .bash_history ban đầu không, tôi không muốn một tệp lịch sử bash khác tồn tại trong $ HOME của tôi 2. Có thể bạn nên cân nhắc đặt repo github cho việc này.
weynhamz

Có vẻ như hook gỡ lỗi bị xung đột với bashdb, đầu ra theo dõi mỗi khi tôi bắt đầu một phiên bash. `` `bash debugger, bashdb, phát hành 4.2-0.8 Bản quyền 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Rocky Bernstein Đây là phần mềm miễn phí, được cấp phép bởi GNU General Public License, và bạn được chào đón thay đổi nó và / hoặc phân phối các bản sao của nó trong những điều kiện nhất định. ** Lỗi gỡ lỗi nội bộ _Dbg_is_file (): đối số tệp null bash: _Dbg_filenames [$ fullname]: đăng ký mảng xấu `` `
weynhamz

@Techlive Zheng: 1. Bản gốc Mạnh mẽ theo thiết kế, sẽ được giữ nguyên. 2. Một repo github là một ý tưởng tốt nói chung, nhưng tôi không có thời gian để duy trì điều đó cho dự án này, vì vậy tôi không làm điều đó. - Có, nó xung đột với bashdb và không có giải pháp dễ dàng nào (họ sử dụng cùng một hook). Tôi không có kế hoạch sửa chữa, nhưng tôi chấp nhận các bản vá.
pts

OK cảm ơn bạn. Tôi đã đưa ra một sulotion đơn giản và tốt hơn nhiều.
weynhamz

@TechliveZheng: Bạn có thể chia sẻ giải pháp đơn giản và tốt hơn của bạn với chúng tôi, để tất cả chúng ta có thể học hỏi từ nó? (Nếu vậy, vui lòng thêm câu trả lời cho câu hỏi.)
pts

8

Bạn có thể sử dụng history -ađể nối lịch sử của phiên hiện tại vào histfile, sau đó sử dụng history -rtrên các thiết bị đầu cuối khác để đọc histfile. 


8

Phải, vì vậy cuối cùng điều này làm tôi khó chịu để tìm một giải pháp tốt:

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

Những gì nó làm là sự hợp nhất của những gì được nói trong chủ đề này, ngoại trừ việc tôi không hiểu tại sao bạn sẽ tải lại lịch sử toàn cầu sau mỗi lệnh. Tôi rất hiếm khi quan tâm đến những gì xảy ra trong các thiết bị đầu cuối khác, nhưng tôi luôn chạy một loạt các lệnh, nói trong một thiết bị đầu cuối:

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

(Ví dụ đơn giản)

Và trong một:

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

Không có cách nào tôi muốn lệnh được chia sẻ


1
Lý do bạn tải lại lịch sử sau mỗi lệnh là vì đó là hành vi được yêu cầu bởi câu hỏi (và vì vậy điều này không thực sự trả lời câu hỏi như được đặt ra).
Michael Homer

2
@MichaelHomer Điểm công bằng. Vui lòng downvote để câu trả lời ở dưới cùng, tuy nhiên, tôi sẽ nhấn mạnh điều này cho OP không nhận ra hành vi được yêu cầu sẽ tệ đến mức nào, và thực tế đây là câu hỏi rất khó hiểu.
Yarek T

3
Op ở đây, yeah, đó là một sự thỏa hiệp công bằng. Khiếu nại chính của tôi là tôi đã mất lịch sử. Điều này sẽ ngăn chặn điều đó, ngay cả khi nó không có nghĩa là cập nhật tức thì qua các phiên đồng thời.
Oli

7

Đây là một thay thế mà tôi sử dụng. Nó cồng kềnh nhưng nó giải quyết vấn đề mà @axel_c đã đề cập trong đó đôi khi bạn có thể muốn có một thể hiện lịch sử riêng biệt trong mỗi thiết bị đầu cuối (một để thực hiện, một cho giám sát, một cho vim, v.v.).

Tôi giữ một tệp lịch sử được nối thêm mà tôi liên tục cập nhật. Tôi có ánh xạ tới một phím nóng sau đây:

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

Điều này sẽ nối tất cả lịch sử từ thiết bị đầu cuối hiện tại vào một tệp có tên master_history.txt trong thư mục nhà của bạn.

Tôi cũng có một phím nóng riêng để tìm kiếm thông qua tệp lịch sử chính:

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

Tôi dùng mèo | grep vì nó để con trỏ ở cuối để vào regex của tôi. Một cách ít xấu xí hơn để làm điều này sẽ là thêm một vài tập lệnh vào đường dẫn của bạn để hoàn thành các nhiệm vụ này, nhưng các phím nóng hoạt động cho mục đích của tôi. Tôi cũng định kỳ sẽ kéo lịch sử xuống từ các máy chủ khác mà tôi đã làm việc và nối lịch sử đó vào tệp master_history.txt của mình.

Thật tuyệt khi có thể nhanh chóng tìm kiếm và tìm thấy regex phức tạp mà bạn đã sử dụng hoặc một lớp lót kỳ lạ mà bạn đã nghĩ ra 7 tháng trước.


6

Tôi có thể cung cấp một bản sửa lỗi cho cái cuối cùng đó: đảm bảo biến env HISTCONTROL không chỉ định "khoảng trống" (hoặc "ignboth").

Nhưng tôi cảm thấy nỗi đau của bạn với nhiều phiên đồng thời. Nó chỉ đơn giản là không xử lý tốt trong bash.


6

Đây là sự nâng cao của tôi đối với câu trả lời của @ lesmana . Sự khác biệt chính là các cửa sổ đồng thời không chia sẻ lịch sử. Điều này có nghĩa là bạn có thể tiếp tục làm việc trong các cửa sổ của mình mà không cần bối cảnh từ các cửa sổ khác được tải vào các cửa sổ hiện tại của bạn.

Nếu bạn gõ rõ ràng 'history', HOẶC nếu bạn mở một cửa sổ mới thì bạn sẽ nhận được lịch sử từ tất cả các cửa sổ trước đó.

Ngoài ra, tôi sử dụng chiến lược này để lưu trữ mọi lệnh đã từng gõ trên máy của mình.

# 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 "$@"
}

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

5

Tôi đã chọn đưa lịch sử vào một tệp mỗi lần, vì nhiều người có thể làm việc trên cùng một máy chủ - việc tách các lệnh của mỗi phiên giúp việc kiểm toán dễ dàng hơn.

# 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

Lịch sử bây giờ trông như:

user@host:~# test 123
user@host:~# test 5451
user@host:~# 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

Với các tập tin trông như:

user@host:~# 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

3

Ở đây tôi sẽ chỉ ra một vấn đề với

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

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

Nếu bạn chạy nguồn ~ / .bashrc, $ PROMPT_COMMAND sẽ giống như

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

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

Sự lặp lại này xảy ra mỗi khi bạn chạy 'source ~ / .bashrc'. Bạn có thể kiểm tra PROMPT_COMMAND sau mỗi lần bạn chạy 'nguồn ~ / .bashrc' bằng cách chạy 'echo $ PROMPT_COMMAND'.

Bạn có thể thấy một số lệnh rõ ràng bị hỏng: "history -n history -a". Nhưng tin tốt là nó vẫn hoạt động, bởi vì các phần khác vẫn tạo thành một chuỗi lệnh hợp lệ (Chỉ liên quan đến một số chi phí bổ sung do thực hiện một số lệnh lặp đi lặp lại. Và không quá sạch sẽ.)

Cá nhân tôi sử dụng phiên bản đơn giản sau:

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

trong đó có hầu hết các chức năng trong khi không có vấn đề như đã đề cập ở trên.

Một điểm khác để thực hiện là: thực sự không có gì kỳ diệu . PROMPT_COMMAND chỉ là một biến môi trường bash đơn giản. Các lệnh trong nó được thực thi trước khi bạn nhận được dấu nhắc bash (dấu $). Ví dụ: PROMPT_COMMAND của bạn là "echo 123" và bạn chạy "ls" trong thiết bị đầu cuối của mình. Hiệu ứng giống như chạy "ls; echo 123".

$ PROMPT_COMMAND="echo 123"

đầu ra (Giống như chạy 'PROMPT_COMMAND = "echo 123"; $ PROMPT_COMMAND'):

123

Chạy như sau:

$ echo 3

đầu ra:

3
123

"history -a" được sử dụng để ghi các lệnh lịch sử trong bộ nhớ vào ~ / .bash_history

"history -c" được sử dụng để xóa các lệnh lịch sử trong bộ nhớ

"history -r" được sử dụng để đọc các lệnh lịch sử từ ~ / .bash_history vào bộ nhớ

Xem giải thích lệnh lịch sử tại đây: http://ss64.com/bash/history.html

PS: Như những người dùng khác đã chỉ ra, xuất khẩu là không cần thiết. Xem: sử dụng xuất trong .bashrc


2

Tôi đã viết một tập lệnh để thiết lập một tệp lịch sử cho mỗi phiên hoặc tác vụ dựa trên các phần sau.

        # 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

Nó không cần thiết lưu mọi lệnh lịch sử nhưng nó lưu những thứ tôi quan tâm và dễ dàng lấy chúng hơn sau đó đi qua mọi lệnh. Phiên bản của tôi cũng liệt kê tất cả các tệp lịch sử và cung cấp khả năng tìm kiếm thông qua tất cả chúng.

Nguồn đầy đủ: https://github.com/simotek/scripts-config/blob/master/hiset.sh


2

Đây là một giải pháp không trộn lẫn lịch sử từ các phiên riêng lẻ!

Về cơ bản, người ta phải lưu trữ lịch sử của từng phiên riêng biệt và tạo lại nó trên mỗi dấu nhắc. Đúng, nó sử dụng nhiều tài nguyên hơn, nhưng nó không chậm như âm thanh - độ trễ bắt đầu chỉ đáng chú ý nếu bạn có hơn 100000 mục lịch sử.

Đây là logic cốt lõi:

# 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

Xem ý chính này để có giải pháp đầy đủ, bao gồm một số biện pháp bảo vệ và tối ưu hóa hiệu suất.


1

Điều này làm việc cho 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

Thật không may, câu hỏi này hoàn toàn dành cho bash :-)
Jaleks

1
Đây là kết quả đầu tiên trên google khi tôi tìm kiếm zsh ... Tôi nghĩ nó có thể giúp
Mulki

3
Bạn nên hỏi một câu hỏi mới, ~ "Bảo tồn lịch sử zsh trong nhiều cửa sổ đầu cuối", giả sử một cái không tồn tại. Điều đó hoàn toàn ổn, bạn đã khuyến khích tinh ranh trả lời câu hỏi của bạn nếu đó là một câu hỏi hay.
Oli

1

Tôi đã muốn điều này từ lâu, đặc biệt là khả năng truy xuất một lệnh bằng cách nó được chạy để thực thi lại trong một dự án mới (hoặc tìm một thư mục bằng một lệnh). Vì vậy, tôi kết hợp công cụ này với nhau, kết hợp các giải pháp trước đây để lưu trữ lịch sử CLI toàn cầu với một công cụ grepping tương tác được gọi là percol (ánh xạ tới C ^ R). Nó vẫn còn mượt trên chiếc máy đầu tiên tôi bắt đầu sử dụng, bây giờ với lịch sử CLI> 2 năm tuổi.

Nó không gây rối với lịch sử CLI cục bộ khi có liên quan đến các phím mũi tên, nhưng cho phép bạn truy cập vào lịch sử toàn cầu khá dễ dàng (bạn cũng có thể ánh xạ tới một thứ khác ngoài C ^ R)


cái này cho zsh?
sjas

1
vâng, tôi đã làm nó cho zsh ban đầu. Có nó làm việc cho bash và cá quá mặc dù. Hãy cho tôi biết nếu nó hoạt động hay không. Tôi đã không thay đổi nó trong một thời gian và tôi không chắc mình đã rõ ràng như thế nào trong hướng dẫn cài đặt của mình
Gordon Wells

1

Bởi vì tôi thích lịch sử vô hạn được lưu trong tập tin tùy chỉnh. Tôi tạo cấu hình này dựa trên 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"

-1

Đây là đoạn trích từ .bashrc của tôi và các giải thích ngắn bất cứ khi nào cần:

# 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 và HISTSIZE là sở thích cá nhân và bạn có thể thay đổi chúng theo sở thích của mình.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.