Lịch sử Bash: Những người bị bỏ qua


84

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 - - Tôi đang ở trên Fedora 15.

Tôi đã thêm phần sau vào .bashrctệp 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ì?

băng! bất kỳ ai? Không có gì hoạt động. Đây có thể là một vấn đề với Fedora 15 (với Gnome 3 và đang chạy trên máy chủ ảo Windows)?
it_me

Xin đừng "đụng" bài viết ở đây. Nếu họ không nhận được câu trả lời, bạn cần hỏi rõ hơn, bao gồm các bit đúng của manh mối bối cảnh hoặc một cái gì đó. Nếu bạn cần chú ý vào bài đăng của mình, bạn có thể phát hành tiền thưởng giúp nhiều người chú ý đến họ hơn.
Caleb

1
Bạn có chắc là bạn thậm chí đang sử dụng bash? ( echo $SHELL). Các cài đặt có hoạt động không nếu bạn chạy chúng thủ công từ vỏ mở của bạn? Rõ ràng vì chúng làm việc cho rất nhiều người khác nên các cài đặt là đúng, bạn chỉ đang thực hiện chúng sai. Và không Fedora15 / Gnome3 / là một máy ảo có liên quan nhiều đến chức năng thực tế của bash.
Caleb

@Caleb, đầu tiên xin lỗi về việc trả bài. Ngoài ra, tôi đã cố gắng hết sức để rất rõ ràng. Không, tôi đã không đưa chúng vào vỏ. Tôi chỉ sao chép-dán chúng vào .bashrctập tin. Là sai đó? Bạn có thể thêm "câu trả lời" cho bài đăng này bằng các lệnh shell thực tế không? (xin vui lòng chịu đựng với noob-ity của tôi.)
it_me

1
Tất cả mọi thứ bạn viết trong các tập lệnh hoặc là .bashrccác lệnh shell thực tế. Các kịch bản chỉ là một loạt các lệnh shell. Ngoài ra, chỉnh sửa gần đây bạn thực hiện loại bỏ exportbit là một ý tưởng tồi, cần được giữ lại.
Caleb

Câu trả lời:


119

Đâ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 Entertrong thiết bị đầu cuối, nơi anh ấy / 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ử.
  • Tùy chọn 2:

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

    (Có, không cần shopt -s histappendvà có, nó phải 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. Các historylệnh có thể cho sản lượng sai - xem dưới đây.

[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à lựa chọn duy nhất để có cả hai erasedupsvà 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 đến từ việc phân tích đầu ra của historylệnh . Trong nhiều trường hợp, lệnh có thể cho đầu ra sai . Tại sao? Bởi vì nó được thực thi trước chuỗi các historylệnh 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 những thay đổi của .bash_historynội dung ( watch -n1 "tail -n20 .bash_history"ví dụ sử dụng ) và xem lịch sử thực sự là gì.

3. Tại sao phương án 3 lại phức tạp như vậy?

Tất cả nằm ở cách erasedupslàm việc. Như hướng dẫn sử dụng bash, "(...) erasedupslàm cho 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 -.lệnh phải hoặc không thể nằm trong PROMPT_COMMAND:

  • history -n được ở đó trước khi history -wđọc từ .bash_historycác lệnh lưu từ mọi thiết bị đầu cuối khác,

  • history -w để có mặt ở đó để cứu lịch sử để nộp và xóa bản sao,

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

  • history -ccũng cần thiết bởi 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 làm cho lịch sử được chia sẻ qua các phiên cuối.


2
+1 cho "Nhưng cách giải thích sai lệch nhất về cách các cài đặt hoạt động đến từ việc phân tích đầu ra của lệnh lịch sử." Tôi nghĩ đây là cốt lõi của vấn đề OP. Khấu trừ tuyệt vời.
jasonwryan

2
Cuối cùng tôi đã thấy quan điểm của bạn. Bởi 'trùng lặp', bạn có ý gì khác ngoài bản thân mình. Tôi chỉ tập trung vào các chuỗi của cùng một lệnh . Cập nhật câu trả lời của tôi - xem "tùy chọn 3". Ngoài ra, đối với trường hợp của bạn, để kiểm tra lịch sử hoạt động như thế nào bạn thực sự nên sử dụng watch "tail -n 20 .bash_history"thay vì tail -f .bash_history.
rozcietrzewiacz

2
Tùy chọn 3 vừa xóa sạch tất cả 100.000 dòng lịch sử của tôi :( (bash 3.2.25 (1) -release)
Felipe Alvarez

2
history -ccũng cần thiết bởi vì nó ngăn chặn việc xóa bộ đệm lịch sử sau mỗi lệnh Tại sao việc dọn rác này xảy ra?
Piotr Dobrogost

2
Giải pháp 3 của bạn thực sự không hoạt động. Nó cực kỳ lỗi và phụ thuộc vào thứ tự người dùng nhấn vào các thiết bị đầu cuối khác nhau. Nó thường sẽ dẫn đến các lệnh bị mất, đặc biệt là khi chuyển đổi qua lại giữa các thiết bị đầu cuối. Nguồn: đã thử nó ra.
6

8

Trong lệnh nhắc của bạn, bạn đang sử dụng -cchuyển đổi. 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 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 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:

Các cmdhist tùy chọn vỏ, nếu được kích hoạt, làm cho vỏ để cố gắng tiết kiệm từng dòng một lệnh đa dòng trong mục nhập lịch sử cùng, thêm dấu chấm phẩy khi cần thiết để bảo tồn đúng đắn cú pháp. Các lithist tùy chọn vỏ làm cho vỏ để lưu các lệnh với newlines nhúng thay vì dấu chấm phẩy.

Ngoài ra, bạn không nên mở đầu 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:erasedupslà đủ.


Vậy, điều này export PROMPT_COMMAND="history -a; history -n; history -r; $PROMPT_COMMAND"có đúng không? Ngoài ra, bạn có biết làm thế nào tôi có thể làm cho tệp lịch sử lưu trữ các lệnh đa dòng dưới dạng một lệnh đơn (được tắt theo mặc định) ??
it_me

1
Đúng. Theo trang man được trích dẫn ở trên, shopt -s cmdhistsẽ lưu nhiều dòng.
jasonwryan

được rồi, tôi đã thử tất cả. Hình như HISTCONTROL=ignoredups:erasedupskhông hoạt động. Tôi cũng đã thử chỉ có trong .bashrctệp (trong số các chức năng tùy chỉnh). Bất cứ ý tưởng những gì có thể là sai? Tôi đang sử dụng Fedora 15 trên máy ảo - - Máy chủ Windows 7.
it_me

Hãy chắc chắn rằng không có gì trong các tệp khởi động khác, như /etc/bashrc, .bash_profilevv đang ghi đè lên nó.
jasonwryan

Tôi không thấy bất kỳ vấn đề với các .bash_profiletập tin. Đối với nội dung trong /etc/bashrctôi đặt nó ở đây, vui lòng xem - pastebin.com/Uae6sE6s
it_me

8

Đâ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!
  • Tôi HISTIGNOREbỏ 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.

1

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

HISTCONTROL=ignoreboth

0

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 có vẻ như history -nchỉ là lỗi khi export HISTCONTROL=ignoreboth:erasedupscó 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ó echolệnh 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 echo "Z"lệnh đó được hợp nhất với history -n.

Một lỗi khác là do 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 hy vọng echocác lệnh khác xuất hiện trong lịch sử


0

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.

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.