Lịch sử BASH rút ngắn thành 500 dòng trên mỗi lần đăng nhập


22

Vì một số lý do, tôi không thể để hệ thống của mình giữ lịch sử BASH sau khi khởi động lại. Dưới đây là các phần có liên quan của tôi ~/.bashrc:

shopt -s histappend
PROMPT_COMMAND='history -a; updateWindowTitle'
export HISTCONTROL=ignoredups
export HISTSIZE=9999
export HISTFILESIZE=999999
export HISTFILE="$HOME/.bash_history"

Theo như tôi có thể nói đó là tất cả các tùy chọn cần thiết (tôi biết tôi đã từng có thể giữ lịch sử trên nhiều lần khởi động lại mà không cần tất cả những điều này trong quá khứ). Tuy nhiên, mặc dù đã thêm các tùy chọn này một vài lần khởi động lại trước đây, tôi vẫn mất phần lớn lịch sử của mình sau khi khởi động lại. Nó không trống, nhưng nó không có 9999 dòng tôi có trước khi khởi động lại.

Trước khi bất cứ ai phàn nàn, vâng tôi đã đọc những câu hỏi này. Tôi đã thực hiện một số đề xuất của họ như được liệt kê ở trên, phần còn lại là không có ích hoặc không liên quan:

Nếu bạn có thể có các lệnh liên quan khác, bạn có thể xem toàn bộ ~/.bashrc ở đây .

Vì vậy, tôi đang thiếu gì? Tại sao lịch sử của tôi không được lưu? Nếu bất cứ ai nghĩ rằng một tập tin khác có thể có liên quan cho tôi biết và tôi sẽ đăng nó. Tôi đã kiểm tra bằng cách chạy grep -i hist \.*trong $HOMEđó cho thấy .tệp duy nhất có chứa chuỗi histhoặc HIST.bashrc.

Tôi đang chạy Linux Mint Debian Edition, GNU bash, phiên bản 4.2.36 (1) -release (x86_64-pc-linux-gnu) và trình giả lập thiết bị đầu cuối yêu thích của tôi (trong trường hợp có liên quan) terminator.


CẬP NHẬT:

Theo đề xuất của @ mpy trong các bình luận, tôi đã thay đổi ~/.bashrcđể đặt HISTFILE=~/bash_historytrái ngược với mặc định ~/.bash_historyvà điều đó dường như giải quyết vấn đề cho các vỏ tương tác . Shell đăng nhập vẫn hiển thị hành vi tương tự, với lịch sử cắt ngắn ở 500các dòng. Tuy nhiên, không HISTcó biến liên quan nào được đặt trong các tệp có liên quan:

$ for f in /etc/profile ~/.profile ~/.bash_profile ~/.bash_login; do \
   echo -ne "$f :"; echo `grep HIST $f`; \
done
/etc/profile :
/home/terdon/.profile :grep: /home/terdon/.profile: No such file or directory
/home/terdon/.bash_profile :grep: /home/terdon/.bash_profile: No such file or directory
/home/terdon/.bash_login :grep: /home/terdon/.bash_login: No such file or directory
$ grep -r HIST /etc/profile.d/  <-- returns nothing

Vì vậy, tại sao là thiết lập HISTSIZEHISTFILESIZEtrong ~/.bashrckhông đủ, trừ khi tôi dứt khoát thiết lập $HISTFILEmột cái gì đó khác hơn so với mặc định ~/.bash_history?


Bạn có phải là chủ sở hữu của .bash_history hoặc root không? Làm ls -l .bash_history
Adnan Bhatti

1
@MSStp vâng, nó thuộc sở hữu của tôi. Cảm ơn về lời đề nghị nhưng tôi không thấy làm thế nào nó có thể là vấn đề về quyền, dù tôi có quyền truy cập đọc / ghi vào nó hay không. Vì một số lịch sử được lưu, tôi rõ ràng làm. Nếu bash có cài đặt gây ra sự cố khi tệp này không thuộc quyền sở hữu của người dùng, nó sẽ khiếu nại hoặc toàn bộ chức năng lịch sử sẽ không hoạt động.
terdon

Khi bạn thực thi historylệnh, đầu ra bạn thấy giống hệt với những gì bạn thấy, đang chạy cat .bash_history, ngoài số dòng? Tôi có nghĩa là historylệnh danh sách thời gian tem hoặc thông tin khác? Lý do tôi hỏi là, nếu bạn thấy những thứ bí truyền này, có nghĩa là, có một mô-đun / chức năng / chương trình khác, đang làm rối tung lịch sử vỏ và một phiên bản sai hoặc lỗi của bất cứ điều gì, có thể gây cho bạn sự đau buồn .
MelBurslan

@Mel_Burslan vâng, nó giống nhau, sự khác biệt duy nhất là số dòng.
terdon

2
Ok, một đề nghị hơi kỳ lạ, nhưng đó cũng là một vấn đề nhức nhối ;): Hãy thử một tệp khác là HISTFILE, không phải mặc định ~/.bash_history. Giải thích rất có cấu trúc: Tôi giả sử bash là shell mặc định của bạn, vì vậy khi hệ thống bắt đầu, shell không tương tác là cha mẹ của phiên X của bạn (tôi cũng giả sử bạn sử dụng X), sẽ không biết gì về tùy chọn histappend (vì .bashrc chỉ đọc bằng các shell tương tác), miễn là shell cha này chạy mọi thứ đều ổn, nhưng sau khi chấm dứt (tức là dừng hệ thống), nó sẽ ghi đè ~/.bash_history(mặc định) và làm rối tung lịch sử của bạn ...
mpy

Câu trả lời:


17

Vấn đề thực sự tập trung vào các hành vi khác nhau của shell đăng nhập và không đăng nhập. Tôi đã thiết lập các biến kiểm soát lịch sử trong của tôi ~/.bahsrc. Tệp này không được đọc khi bắt đầu một vỏ đăng nhập, nó chỉ được đọc bởi các vỏ tương tác, không đăng nhập (từ man bash):

Khi bash được gọi dưới dạng shell đăng nhập tương tác hoặc dưới dạng shell không tương tác với --logintùy chọn, đầu tiên nó sẽ đọc và thực thi các lệnh từ tệp /etc/profile, nếu tệp đó tồn tại. Sau khi đọc tệp đó, nó tìm ~ / .bash_profile, ~/.bash_login~/.profile, theo thứ tự đó, đọc và thực thi các lệnh từ cái đầu tiên tồn tại và có thể đọc được. Các --noprofiletùy chọn có thể được sử dụng khi vỏ được bắt đầu để ức chế hành vi này.

[. . . ]

Khi một vỏ tương tác không phải là vỏ đăng nhập được khởi động, bash sẽ đọc và thực thi các lệnh từ ~ / .bashrc, nếu tệp đó tồn tại. Điều này có thể bị ức chế bằng cách sử dụng tùy chọn --norc. Tùy chọn tệp --rcfile sẽ buộc bash đọc và thực thi các lệnh từ tệp thay vì ~ / .bashrc.

Do đó, mỗi lần tôi đăng nhập hoặc giảm xuống một tty hoặc sử dụng ssh, .historytệp sẽ bị cắt ngắn vì tôi cũng không đặt đúng kích cỡ ~/.profile. Cuối cùng tôi đã nhận ra điều này và chỉ cần đặt các biến ở ~/.profile nơi chúng thuộc về , thay vì~/.bashrc

Vì vậy, lý do khiến tôi ~/.historybị cắt ngắn là vì tôi chỉ đặt các biến HISTORY trong một tệp được đọc bởi các vỏ tương tác, không đăng nhập và do đó mỗi khi tôi chạy một loại vỏ khác nhau, các biến sẽ bị bỏ qua và tệp sẽ bị cắt phù hợp.


Điểm rất tốt, cảm ơn vì đã chia sẻ! Tuy nhiên, tôi không đồng ý với: Tệp này không được đọc khi bắt đầu một vỏ đăng nhập, nó chỉ được đọc bởi các vỏ tương tác. Bởi vì một vỏ đăng nhập cũng có thể tương tác. Nếu không, toàn bộ cơ chế lịch sử sẽ không có ý nghĩa. IMHO .bashrckhông được đọc bởi (shell đăng nhập HOẶC không tương tác).
mpy

@mpy Thật vậy, xin lỗi, ý tôi là shell tương tác, không đăng nhập. Trả lời chỉnh sửa.
terdon

1
@terdon, thành ngữ phổ biến là các tùy chọn shell tương tác không đi vào ~ / .profile hoặc ~ / .bash_profile. Các tùy chọn vỏ tương tác được đưa vào ~ / .bashrc. Để tránh phải duy trì cài đặt ở hai vị trí, các lệnh sau có thể được đặt ở đầu a ~ / .bash_profile: export BASH_ENV=~/.bashrc ; if [ -f ~/.bashrc ]; then . ~/.bashrc; fi... và ở đầu ~ / .bashrc đặt một kiểm tra để đảm bảo bạn thực sự đang chạy tương tác: [ -z "$PS1" ] && return... Tất nhiên, đó chỉ là một thành ngữ.
Noah Spurrier

1
@NoahSpurrier BASH_ENVkhông liên quan, nó chỉ ảnh hưởng đến các shell không tương tác. Đối với "thành ngữ", đó là điều mà Debian bắt đầu và cá nhân tôi không đồng ý. Tôi thường có các tùy chọn đồ họa ( xsetvà tương tự) trong .bashrc của mình và tôi không muốn chúng hoạt động khi tôi chạy shell đăng nhập từ một tty hoặc thông qua ssh. Tôi muốn .profile và .bashrc riêng biệt. Nhiều (mặc dù không phải tất cả) người quản lý đăng nhập nguồn .profile khi bạn đăng nhập để các biến toàn cục được đặt tốt nhất ở đó chúng sẽ chỉ được đọc một lần và không phải mỗi lần bạn mở một thiết bị đầu cuối.
terdon

1
@WilsonF có. Các tệp được đọc tuần tự và các tệp cá nhân ( ~/.profilehoặc ~/.bashrc) được đọc sau cùng. Bất cứ điều gì được đặt trong đó sẽ được ưu tiên hơn các cài đặt toàn cầu. Bạn hoàn toàn đúng, bạn không nên đặt các biến đó vào /etc/bash.bashrc. Sử dụng ~/.profile(hoặc ~/.bash_profile) thay thế.
terdon

11

Đề nghị của tôi là sử dụng một tập tin khác HISTFILE, không phải mặc định ~/.bash_history.

Mặc dù tôi không có lời giải thích phân tích, tôi sẽ cố gắng phác thảo điều gì đã đưa tôi đến gợi ý này: Nếu bạn sử dụng bashlàm vỏ (đăng nhập) mặc định của mình và cũng sử dụng X(cả hai đều rất có thể) bạn có một bashví dụ đang chạy ngay sau (đồ họa ) đăng nhập:

systemd
 ...
  |-login
  |   `-bash      <<====
  |       `-slim
  |           |-X -nolisten tcp vt07 -auth /var/run/slim.auth
  |           |  `-{X}
  |           `-fluxbox
  |               `-xterm -bg black -fg white
  |                   `-bash
 ...

Tôi nghĩ rằng trường hợp này là một vỏ đăng nhập, vì vậy nó không đọc của bạn ~/.bashrcvà do đó sẽ không biết gì về histappendtùy chọn:

man bash (1) : Khi shell tương tác không phải là shell đăng nhập được khởi động, bash đọc và thực thi các lệnh từ /etc/bash.bashrc và ~ / .bashrc, nếu các tệp này tồn tại. (...)

Miễn là "lớp vỏ mẹ" này chạy, mọi thứ đều ổn, nhưng khi chấm dứt (tức là dừng hệ thống), nó sẽ ghi đè ~/.bash_history(vì đó là giá trị mặc định) và làm rối lịch sử của bạn hoặc clip trên hệ thống bắt đầu (lại mặc định) 500 dòng. (Hoặc có lẽ cả hai ...)

Tôi cũng nhận ra rằng nó không đủ để bao gồm cấu hình lịch sử ~/.bashrc, vì đây không phải là một thiết lập không phổ biến. Tôi không có lời giải thích cho điều đó.


Liên quan đến vấn đề của bạn, rằng "Shell đăng nhập vẫn hiển thị cùng một hành vi", bạn có thể thử đưa cấu hình lịch sử vào ~/.bash_profile:

man bash (1) : Khi bash được gọi dưới dạng shell đăng nhập tương tác hoặc dưới dạng shell không tương tác với tùy chọn --login, trước tiên, nó sẽ đọc và thực thi các lệnh từ tệp / etc / profile, nếu tệp đó tồn tại. Sau khi đọc tệp đó, nó sẽ tìm ~ / .bash_profile, (...)

Thật không may, tôi không thể đăng một lời giải thích hợp lý hơn với các chi tiết từ bashcấu hình của riêng tôi , vì tôi là một zshchàng trai ...


2
Hoàn toàn thiết lập các tùy chọn lịch sử trong tôi đã ~/.bash_profilegiải quyết vấn đề. Bây giờ tôi đang sử dụng ~/.bash_historylàm tệp lịch sử của mình nhưng chỉ cần thêm tất cả các dòng từ ~/.bashrchiển thị trong câu hỏi của tôi vào ~/.bash_profile. Vẫn không chắc ai đã làm hỏng vỏ tương tác, nhưng có vẻ như bây giờ nó hoạt động, cảm ơn!
terdon

1
Xin lỗi vì không chấp nhận nhưng tôi đã quên đăng câu trả lời giải thích chuyện gì đang xảy ra. Tôi đã tìm ra nó với một số trợ giúp từ @Gilles một thời gian trước và cuối cùng đã làm tròn để gửi câu trả lời. Tôi muốn chấp nhận của tôi vì nó thực sự giải thích vấn đề thay vì đưa ra một cách giải quyết (rất tốt) và có thể giúp khách truy cập trong tương lai.
terdon

2

Vì tất cả các cài đặt của bạn theo thứ tự theo trang man và vì tệp lịch sử không bị giới hạn bởi kích thước (byte), nên tôi chỉ có thể giải thích. Nó phải làm như thế nào vỏ chết.

Theo tài liệu tham khảo trực tuyến, lối thoát duyên dáng (lịch sử đã lưu) chỉ xảy ra khi trình bao nhận được SIGHUP. Tôi thực sự không thể giải thích cách hệ thống của bạn truyền tín hiệu khi được khởi động lại, nhưng tôi nghi ngờ rằng trình bao của bạn thoát ra với SIGKILL hoặc SIGPWR.

Điều này có thể là do WM của bạn chạy không đồng bộ (chờ) và trình giả lập thiết bị đầu cuối sinh ra từ WM nơi bash nhận được tín hiệu buộc thoát ra ngoài SIGHUP. Hệ điều hành cũng có thể nhanh chóng gửi "tiêu diệt cuối cùng" tới tất cả các quy trình trước khi SIGHUP duyên dáng ban đầu quản lý để lấy vỏ thông qua X -> WM -> xterm, có thể vì X hoặc WM mất nhiều thời gian để thoát hơn phải mất cho hệ điều hành để sẵn sàng để đi xuống.

Tôi đang ở vùng nước sâu với những thứ này, nhưng tôi nghĩ rằng một cái gì đó dọc theo những dòng đó gây ra hành vi thất thường. Tôi đã có vấn đề này trước đây, và biện pháp khắc phục chắc chắn nhất là exittrong bash nơi bạn muốn giữ lịch sử.

Tôi nhận thấy history -atrong câu hỏi của bạn và tôi không thể nghĩ tại sao điều đó không đủ để bảo tồn lịch sử.

Bạn có thể khắc phục sự cố bằng cách tìm ra cái gì thực sự giết chết bash của bạn và chuyển sang tìm ra tín hiệu bắt nguồn từ đâu và khắc phục sự cố ở đó, hoặc đơn giản là xóa lịch sử khi bạn biết tín hiệu nào là cuối cùng (giả sử đĩa vẫn còn trực tuyến ):

trap "echo got 1  >/tmp/sig1;  exit" SIGHUP
trap "echo got 2  >/tmp/sig2;  exit" SIGINT
trap "echo got 15 >/tmp/sig15; exit" SIGTERM
 .. and so on...

Ảnh chụp màn hình bao gồm minh họa những gì tôi đang nói trong đoạn thứ hai và thứ ba. Trình tự có tôi vỏ từ trái , giết vỏ trái từ phải và mèo lịch sử.

người đàn ông bash

Khi khởi động, (...) Tệp được đặt tên theo giá trị của HISTFILE bị cắt ngắn, nếu cần, để chứa không quá số lượng dòng được chỉ định bởi giá trị của HISTFILESIZE (+ mặc định 500).

Nếu tùy chọn shell histappend được bật (+ mặc định ở đây), các dòng được gắn vào tệp lịch sử, nếu không, tệp lịch sử sẽ bị ghi đè.

tài liệu tham khảo trực tuyến

3.7.6 Tín hiệu

Khi Bash tương tác, trong trường hợp không có bất kỳ bẫy nào, nó sẽ bỏ qua SIGTERM (để 'kill 0' không giết được vỏ tương tác), và SIGINT bị bắt và xử lý (do đó, nội dung chờ đợi bị gián đoạn). Khi Bash nhận được SIGINT, nó thoát ra khỏi bất kỳ vòng lặp thực thi nào. Trong mọi trường hợp, Bash bỏ qua SIGQUIT. Nếu kiểm soát công việc có hiệu lực (xem Kiểm soát công việc), Bash sẽ bỏ qua SIGTTIN, SIGTTOU và SIGTSTP.

Các lệnh không dựng sẵn được bắt đầu bởi Bash có các trình xử lý tín hiệu được đặt thành các giá trị được kế thừa bởi trình bao từ mẹ của nó. Khi điều khiển công việc không có hiệu lực, các lệnh không đồng bộ sẽ bỏ qua SIGINT và SIGQUIT ngoài các trình xử lý được kế thừa này. Các lệnh chạy như là kết quả của việc thay thế lệnh bỏ qua các tín hiệu điều khiển công việc do bàn phím tạo ra SIGTTIN, SIGTTOU và SIGTSTP.

Shell thoát theo mặc định khi nhận được SIGHUP. Trước khi thoát, một vỏ tương tác gửi lại SIGHUP cho tất cả các công việc, đang chạy hoặc dừng. Các công việc đã dừng được gửi SIGCONT để đảm bảo rằng họ nhận được SIGHUP. Để ngăn vỏ gửi tín hiệu SIGHUP đến một công việc cụ thể, nó phải được xóa khỏi bảng công việc với phần dựng sẵn (xem phần Điều khiển công việc) hoặc được đánh dấu để không nhận SIGHUP bằng cách sử dụng -h.

Nếu tùy chọn vỏ huponexit đã được đặt với shopt (xem Cửa hàng được xây dựng), Bash sẽ gửi SIGHUP cho tất cả các công việc khi thoát khỏi vỏ đăng nhập tương tác.

Nếu Bash đang chờ lệnh hoàn thành và nhận được tín hiệu đặt bẫy, bẫy sẽ không được thực thi cho đến khi lệnh hoàn thành. Khi Bash đang chờ lệnh không đồng bộ thông qua nội dung chờ, việc nhận tín hiệu đặt bẫy sẽ khiến cho lệnh chờ được trả về ngay lập tức với trạng thái thoát lớn hơn 128, ngay sau đó bẫy được thực thi.

chụp màn hình trình diễn

tín hiệu


Tôi không thực sự hiểu những gì bạn đang làm trong ảnh chụp màn hình đó. Cái /tmp/psomà bạn đang giết là gì? Tôi thấy quan điểm của bạn về các tín hiệu tiêu diệt khác nhau (mặc dù như bạn nói, tôi nghĩ đó là những gì history -ađang có để đối phó). Tôi sẽ kiểm tra điều đó một lúc và báo cáo lại.
terdon

$ Cat tmp / ps * \ n ps -o pid = | đầu -n1> ~ / tmp / PSO \ n 17201 \ n
Ярослав Рахматуллин

0

Kiểm tra / etc / profile và /etc/profile.d/*

Có lẽ có một cái gì đó lộn xộn với các thiết lập lịch sử ở đó.


Cảm ơn, nhưng grep -r HIST /etc/profile.d/không trả lại gì, và tôi đã kiểm tra rồi /etc/profile.
terdon
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.