it-swarm-vi.com

Lịch sử Bash: "bỏ qua" và "xóa" thiết lập xung đột với lịch sử chung giữa các phiên

Trước hết, đây không phải là bản sao của bất kỳ chủ đề hiện có nào trên SE. Tôi đã đọc hai chủ đề này ( thứ 1 , thứ 2 ) về lịch sử bash tốt hơn, nhưng không có câu trả lời nào hoạt động - - Nhân tiện, tôi đang ở Fedora 15.

Tôi đã thêm phần sau vào .bashrc tập tin trong thư mục người dùng (/ home/aahan /) và nó không hoạt động. Bất cứ ai cũng có một đầu mối?

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

Được rồi, đây là những gì tôi muốn với lịch sử bash (ưu tiên):

  • không lưu trữ các bản sao, xóa bất kỳ cái nào hiện có
  • chia sẻ ngay lịch sử với tất cả các thiết bị đầu cuối mở
  • luôn luôn nối lịch sử, không ghi đè lên nó
  • lưu trữ các lệnh nhiều dòng dưới dạng một lệnh (được tắt theo mặc định)
  • kích thước lịch sử mặc định và kích thước tệp lịch sử là gì?
92
its_me

Đây thực sự là một hành vi thực sự thú vị và tôi thú nhận rằng tôi đã đánh giá rất thấp câu hỏi ngay từ đầu. Nhưng trước tiên là sự thật:

1. Những gì hoạt động

Các chức năng có thể đạt được theo nhiều cách, mặc dù mỗi cách hoạt động hơi khác nhau. Lưu ý rằng, trong mỗi trường hợp, để lịch sử "được chuyển" sang thiết bị đầu cuối khác (được cập nhật), người ta phải nhấn Enter trong nhà ga, nơi anh/cô ấy muốn lấy lại lịch sử.

  • lựa chọn 1:

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

    Điều này có hai nhược điểm:

    1. Khi đăng nhập (mở một thiết bị đầu cuối), lệnh cuối cùng từ tệp lịch sử được đọc hai lần vào bộ đệm lịch sử của thiết bị đầu cuối hiện tại;
    2. Bộ đệm của các thiết bị đầu cuối khác nhau không đồng bộ với tệp lịch sử.
  • lựa chọn 2:

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

    (Có, không cần shopt -s histappend và vâng, nó phải là history -c ở giữa Prompt_COMMAND) Phiên bản này cũng có hai nhược điểm quan trọng:

    1. Các tập tin lịch sử phải được khởi tạo. Nó phải chứa ít nhất một dòng không trống (có thể là bất cứ thứ gì).
    2. Lệnh history có thể cung cấp đầu ra sai - xem bên dưới.

[Chỉnh sửa] "Và người chiến thắng là ..."

  • tùy chọn 3 :

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

    Điều này là như xa như nó được. Đó là tùy chọn chỉ để có cả erasedups và lịch sử chung hoạt động đồng thời. Đây có lẽ là giải pháp cuối cùng cho tất cả các vấn đề của bạn, Aahan.


2. Tại sao tùy chọn 2 dường như không hoạt động (hoặc: những gì thực sự không hoạt động như mong đợi)?

Như tôi đã đề cập, mỗi giải pháp trên hoạt động khác nhau. Nhưng cách giải thích sai lệch nhất về cách các cài đặt hoạt động xuất phát từ việc phân tích đầu ra của lệnh history. Trong nhiều trường hợp, lệnh có thể cho false đầu ra. Tại sao? Bởi vì nó được thực thi trước chuỗi các lệnh history khác có trong Prompt_COMMAND! Tuy nhiên, khi sử dụng tùy chọn thứ hai hoặc thứ ba, người ta có thể theo dõi các thay đổi của .bash_history nội dung (sử dụng watch -n1 "tail -n20 .bash_history" chẳng hạn) và xem lịch sử thực sự là gì.

3. Tại sao tùy chọn 3 quá phức tạp?

Tất cả nằm ở cách erasedups hoạt động. Khi hướng dẫn sử dụng bash, "(...) erasedups khiến tất cả các dòng trước khớp với dòng hiện tại bị xóa khỏi danh sách lịch sử trước khi dòng đó được lưu" . Vì vậy, đây thực sự là những gì OP muốn (và không chỉ, như tôi nghĩ trước đây, không có bản sao xuất hiện theo trình tự) . Đây là lý do tại sao mỗi history -. các lệnh phải hoặc không thể nằm trong Prompt_COMMAND:

  • history -n để có mặt trước history -w để đọc từ .bash_history các lệnh được lưu từ bất kỳ thiết bị đầu cuối nào khác,

  • history -whas ở đó để lưu lịch sử vào tệp và xóa các bản sao,

  • history -akhông được được đặt ở đó thay vì history -w, vì nó không kích hoạt xóa các bản sao,

  • history -c cũng là cần thiết vì nó ngăn chặn việc xóa bộ đệm lịch sử sau mỗi lệnh,

  • và cuối cùng, history -rcần thiết để khôi phục bộ đệm lịch sử từ tệp, do đó cuối cùng sẽ tạo lịch sử được chia sẻ qua các phiên cuối.

126
rozcietrzewiacz

Trong lệnh Nhắc của bạn, bạn đang sử dụng -c công tắc điện. Từ man bash:

- c Xóa danh sách lịch sử bằng cách xóa tất cả các mục

Để chia sẻ lịch sử của bạn với tất cả các thiết bị đầu cuối đang mở, bạn có thể sử dụng -n:

- n Đọc các dòng lịch sử chưa được đọc từ tệp lịch sử vào danh sách lịch sử hiện tại. Đây là những dòng được nối vào tệp lịch sử kể từ khi bắt đầu phiên bash hiện tại.

Kích thước mặc định cũng có trong hướng dẫn:

LỊCH SỬ Số lượng các lệnh cần nhớ trong lịch sử lệnh (xem LỊCH SỬ bên dưới). Giá trị mặc định là 500.

Để lưu các lệnh nhiều dòng:

Tùy chọn cmdhist Shell, nếu được bật, sẽ khiến Shell cố gắng lưu từng dòng của một lệnh nhiều dòng trong cùng một mục lịch sử, thêm dấu chấm phẩy khi cần để duy trì tính chính xác cú pháp. Tùy chọn lithist Shell khiến Shell lưu lệnh bằng các dòng mới được nhúng thay vì dấu chấm phẩy.

Ngoài ra, bạn không nên đặt trước các lệnh HIST * với export - chúng là các biến chỉ bash chứ không phải biến môi trường: HISTCONTROL=ignoredups:erasedups là đủ.

8
jasonwryan

Đây là những gì tôi nghĩ ra và tôi hài lòng với nó cho đến nay

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" 

GHI CHÚ:

  • Vâng, nó rất phức tạp ... nhưng, nó loại bỏ tất cả các bản sao và vẫn giữ nguyên thời gian trong mỗi thiết bị đầu cuối!
  • HISTIGNORE của tôi bỏ qua tất cả các lệnh không có đối số. Điều này có thể không được mong muốn bởi một số người và có thể bị bỏ rơi.
8
user41176

Sử dụng cái này thay thế:

HISTCONTROL=ignoreboth
1
verndog

Nó không hoạt động, bởi vì bạn quên đi:

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

Nhưng dường như history -n chỉ là lỗi khi export HISTCONTROL=ignoreboth:erasedups có hiệu lực.

Cho phép thử nghiệm:

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

Ở đây chúng tôi bật dups xóa, chuyển lịch sử sang tập tin tùy chỉnh, xóa lịch sử. Sau khi hoàn thành tất cả các lệnh, chúng ta có tệp lịch sử trống và một lệnh tại lịch sử hiện tại.

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

Mở terminal thứ hai và chạy sáu lệnh đó. Sau đó:

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

Bây giờ lịch sử hiện tại của bạn có hai lệnh và tệp lịch sử có:

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

Quay lại thiết bị đầu cuối đầu tiên:

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

Huh ... không có lệnh echo nào được đọc. Chuyển sang thiết bị đầu cuối thứ hai một lần nữa và:

$ echo "Z"
$ history -w

Bây giờ tệp lịch sử là:

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

Chuyển sang thiết bị đầu cuối một lần nữa:

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

Bạn có thể thấy rằng echo "Z" Lệnh được hợp nhất thành history -n.

Một bug là vì các lệnh được đọc từ lịch sử theo số lệnh chứ không phải theo thời gian lệnh, tôi nghĩ vậy. Tôi mong đợi các lệnh echo khác xuất hiện trong lịch sử

0
Eugen Konkov

Tôi đã đi với một sự kết hợp của câu trả lời ở đây:

  • Tôi muốn lịch sử của tôi được hợp nhất vào cuối, vì vậy tôi đã sử dụng chức năng bẫy.
  • Tôi cũng muốn các tệp lịch sử của mình được phân tách bằng các máy chủ vì vậy tôi đã thay đổi HISTFILE để trỏ đến một thư mục và các tệp được đặt tên tùy thuộc vào tên máy chủ.
  • Tôi đã thêm tùy chọn bỏ qua để tôi có thể nhập mật khẩu văn bản rõ ràng và không để chúng hiển thị trên lịch sử, ví dụ: $ ./.secretfunction -user myuser -password mypassword sẽ không được lưu vì nó bắt đầu bằng không gian.
  • Tôi đã thêm history*exit đến HISTIGNORE chỉ để giữ các lệnh đó bao gồm mọi thứ trong quá khứ như history | grep awesomecommand ra khỏi đó vì tôi thường không muốn nó. Bạn có thể thêm những người khác như: đăng xuất, fg, bg, v.v.
  • Sau đó, tôi đặt tất cả vào tệp ~/.bash_aliases của mình để nó không xung đột với các bản nâng cấp như đôi khi nó đã xảy ra.
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 your ~/for Prompt_COMMAND để đảm bảo bạn không nhận được sửa đổi với lịch sử -a. Tôi cũng đã thêm định dạng TIME/DATE HISTTIMEFORMAT="%x %r %Z " Tôi thích nhưng không bao gồm trong khối trên vì đó là địa phương nhạy cảm.

0
Marlon

erasingups không cắt (như chomp trong một số ngôn ngữ) không gian hàng đầu và dấu. Đây là một lỗi. Ngoài ra xóa không xóa tất cả các mục trước.

0
Sajith Nallithodi

Sử dụng kết hợp tùy chọn 3 của @ rozcietrzewiacz với bẫy thoát sẽ cho phép các thiết bị đầu cuối duy trì các phiên lịch sử độc lập của riêng chúng hội tụ chặt chẽ. Nó thậm chí dường như hoạt động tốt với nhiều phiên trên các máy khác nhau chia sẻ một thư mục nhà từ xa.

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"
  • Hàm historymerge tải các dòng ngoài phiên từ tệp lịch sử, kết hợp chúng với lịch sử phiên, viết ra một tệp lịch sử mới với sự trùng lặp (do đó xóa bất kỳ dòng trùng lặp nào được thêm vào trước đó) và tải lại lịch sử.

  • Duy trì history -a trong Dấu nhắc giảm thiểu khả năng mất lịch sử, vì nó cập nhật tệp lịch sử mà không bị trùng lặp trên mỗi lệnh.

  • Cuối cùng, bẫy kích hoạt historymerge trên phiên đóng cho tệp lịch sử sạch cập nhật với các lệnh của phiên đóng gần đây nhất đã sủi bọt đến cuối tệp (tôi nghĩ).

Với điều này, mỗi phiên cuối sẽ có lịch sử độc lập riêng bắt đầu từ khi khởi chạy. Tôi thấy rằng hữu ích hơn khi tôi có xu hướng mở các thiết bị đầu cuối khác nhau cho các nhiệm vụ khác nhau (do đó tôi muốn lặp lại các lệnh khác nhau trong mỗi nhiệm vụ). Nó cũng đơn giản hơn nhiều so với việc tạo ra nhiều thiết bị đầu cuối liên tục cố gắng đồng bộ lại lịch sử đã ra lệnh theo kiểu phân tán (mặc dù bạn vẫn có thể cố tình sử dụng chức năng historymerge với các phiên chọn hoặc Tất cả bọn họ).

Lưu ý rằng bạn sẽ muốn giới hạn kích thước của mình đủ lớn để giữ độ dài lịch sử mong muốn cộng khối lượng các dòng không trùng lặp có thể được thêm vào bởi tất cả các phiên hoạt động đồng thời. 5000 là đủ cho tôi phần lớn nhờ vào việc sử dụng rộng rãi HISTIGNORE để lọc các lệnh có giá trị thấp spam.

0
HonoredMule