it-swarm-vi.com

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

Tôi luôn có nhiều hơn một 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 ls trong một, chuyển sang thiết bị đầu cuối khác đang chạy và sau đó nhấn lên, ls xuất hiện)
  • 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?

565
Oli

Thêm phần sau vào ~/.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.

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

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.

257
kch

Đâ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ư !number Sẽ 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 "[email protected]"
}

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ẽ khiến $HISTFILE Phát triển theo một dòng.

  2. Đặt biến đặc biệt $HISTFILESIZE Thành một số giá trị sẽ khiến Bash cắt bớt $HISTFILE Không dài hơn $HISTFILESIZE 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ẽ giảm bộ đếm lịch sử theo số lượng $HISTSIZE.

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

  5. Hàm history() 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ử đã giảm $HISTSIZE. Trong bước 4, bộ đếm lịch sử được tăng theo số lượng dòng trong $HISTFILE. Ở bước 2, chúng tôi đảm bảo rằng số dòng của $HISTFILE Chính xác là $HISTSIZE (Điều này có nghĩa là $HISTFILESIZE Phải giống với $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 nên luôn luôn tra cứu số ngay lập tức trước khi sử dụng. Điều đó có nghĩa là không có bash Prompt hiển thị 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 Bash Prompt. 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 hàm _bash_history_sync() để nó không thực thi mỗi lần. Ví dụ: nó không nên thực thi sau CTRL+C Trên Dấ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 tập lệnh 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.

123
lesmana

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 zsh hơn bash vì vậy tôi khuyên bạn nên thử nó.

Đây là một phần trong .zshrc Của tôi liê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
45
Maciej Piechotka

Để 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 đè.

17
Chris Down

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`

.

Khi bạn đã có biến PS1 của mình 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 Lời 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 -r trên mỗi Nhắc.

11
Schof

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 9999 và (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 9999 trong 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_COMMAND hoặc là PS1, cả hai đều thực thi quá muộn, chỉ sau sleep 9999 lệnh đã kết thúc.

10
pts

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ẻ

9
Yarek T

Bạn có thể 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 -r trên các thiết bị đầu cuối khác để đọc histfile.

9
jtimberman

Đâ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 Perl one-liner kỳ lạ mà bạn đã đưa ra 7 tháng trước.

8
Toby

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.

7
jmanning2k

Đây là sự nâng cao của tôi đối với @ lesmana's câu trả lời . 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 nhập rõ ràng 'history', OR 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 tôi.

# 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

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ư:

[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

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

[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

Ở đâ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 'source ~/.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 bash Prompt (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 là không cần thiết. Xem: sử dụng xuất trong .bashrc

5
fstang

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

3
simotek

Đây là một giải pháp mà 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 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 Gist này để biết 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.

3
Jan Warchoł

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"
2
Eugen Konkov

Đ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
2
Mulki

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 đặt công cụ này cùng nhau, kết hợp các giải pháp trước đó để 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)

2
Gordon Wells

Đâ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.

0
Hopping Bunny