bash_history: nhận xét các lệnh nguy hiểm: `#`


16

Để ngăn việc ghi nhật ký các lệnh "nguy hiểm" trong lịch sử bash, tôi đã thêm dòng sau vào .bashrctệp của mình :

HISTIGNORE='rm *:mv *:cp *:cat*>*:pv*>*'

Điều này hoạt động tốt, nhưng nó có tác dụng phụ: Tôi không thể thấy lịch sử đầy đủ của các lệnh được thực thi trên máy. Giả sử tôi có một số máy để thử nghiệm và tôi muốn có thể thấy tất cả các lệnh được thực thi. Tôi sẽ sử dụng bash Internal historyđể hiển thị các lệnh đã thực hiện và có lẽ grep cho ngày hôm nay:

history | grep Sep-28

Những gì tôi muốn có là ghi nhật ký các lệnh "nguy hiểm", nhưng đặt một dòng #ở đầu dòng, để nếu tôi tình cờ thực hiện lệnh từ lịch sử do nhầm lẫn, sẽ không có thiệt hại nào được thực hiện.

Tôi không có ý tưởng nếu điều này là có thể.

Cập nhật và làm rõ:

Lý do chính tại sao đây là một vấn đề đối với tôi là vì tôi thường được kết nối với máy của mình từ một số thiết bị đầu cuối và bất kỳ lệnh nào được thực hiện trên một thiết bị đầu cuối sẽ ngay lập tức được đọc vào lịch sử của các thiết bị đầu cuối khác. Điều này đạt được bởi

PROMPT_COMMAND="history -a; history -c; history -r"

Hãy tưởng tượng tôi có hai thiết bị đầu cuối mở. Trong một tôi có một số cat /dev/foo > file.outquá trình chạy. Trong lần thứ hai, tôi kiểm tra tiến độ với ls -lAhF. Tôi tiếp tục lặp lại lsbằng cách nhấn UpENTER(đó là lệnh cuối cùng từ lịch sử). Ngay khi lệnh đầu tiên kết thúc, lệnh cuối cùng trong lịch sử không còn nữa ls, nhưng cat /dev/foo > file.out. Nếu tôi không cẩn thận, tôi sẽ bắt đầu lại mèo và ghi đè lên file.out.

Những gì tôi muốn đạt được là lệnh mèo sẽ được đi trước với một #, để nó sẽ không được thực thi. Tuy nhiên, tôi vẫn sẽ thấy nó trong lịch sử và có thể sử dụng lại nó (nếu đó là một lệnh dài) bằng cách không bình luận nó.


Thay vì lặp lại lệnh của bạn bằng tay, bạn có thể sử dụng watch ls -lAhFhoặc while sleep 1; do ls -lAhf; done; thay vì xem kích thước tệp, bạn có thể sử dụng pv /dev/foo > file.out( ivarch.com/programs/pv.shtml ).
deltab

Câu trả lời:


9

Bạn có thể làm một cái gì đó như:

fixhist() {
   local cmd histnum
   cmd=$(HISTTIMEFORMAT=/ history 1)
   histnum=$((${cmd%%[*/]*}))
   cmd=${cmd#*/} # remove the histnum
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       history -s "#$cmd"    # add back with a #
   esac
}
PROMPT_COMMAND=fixhist

Ý tưởng được rằng trước mỗi nhanh chóng, chúng tôi kiểm tra sự xâm nhập lịch sử cuối cùng ( history 1) và nếu một trong những nó nguy hiểm người, chúng ta xóa nó ( history -d) và thêm nó trở lại với một #với history -s.

(rõ ràng, bạn cần phải xóa HISTIGNOREcài đặt của bạn ).

Một tác dụng phụ không mong muốn của điều đó là nó làm thay đổi thời gian lịch sử của những lệnh đó rm, mv....

Để khắc phục điều đó, một giải pháp thay thế có thể là:

fixhist() {
   local cmd time histnum
   cmd=$(HISTTIMEFORMAT='<%s>' history 1)
   histnum=$((${cmd%%[<*]*}))
   time=${cmd%%>*}
   time=${time#*<}
   cmd=${cmd#*>}
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       HISTFILE=/dev/stdin history -r <<EOF
#$time
#$cmd
EOF
   esac
}
PROMPT_COMMAND=fixhist

Lần này, chúng tôi ghi lại thời gian của lịch sử cuối cùng và để thêm lại dòng lịch sử, chúng tôi sử dụng history -rtừ một tệp tạm thời (tài liệu ở đây) bao gồm dấu thời gian.

Bạn muốn fixhistthực hiện trước history -a; history -c; history -r. Thật không may, phiên bản hiện tại bashcó một lỗi trong đó history -akhông lưu dòng bổ sung mà chúng tôi đã thêm. Một công việc xung quanh là viết nó thay thế:

fixhist() {
   local cmd time histnum
   cmd=$(HISTTIMEFORMAT='<%s>' history 1)
   histnum=$((${cmd%%[<*]*}))
   time=${cmd%%>*}
   time=${time#*<}
   cmd=${cmd#*>}
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       history -a
       [ -f "$HISTFILE" ] && printf '#%s\n' "$time" "$cmd" >> "$HISTFILE";;
     (*)
       history -a
   esac
   history -c
   history -r
}
PROMPT_COMMAND=fixhist

Đó là nối thêm lệnh đã nhận xét vào HISTFILE thay vì cho phép history -athực hiện.


bạn có thể vui lòng giải thích những gì cmd=${cmd#*[0-9] }không? Và chính xác tôi nên đặt fixhistở đâu PROMPT_COMMAND? Hiện tại, nó đã có sẵnPROMPT_COMMAND="history -a; history -c; history -r"
Martin Vegter

vai trò của là HISTTIMEFORMAT=/gì? Tôi đã thiết lập rồi export HISTTIMEFORMAT="%b-%d %H:%M ". Nhân tiện, khi tôi thêm mã của bạn vào $HOME/.bashrc, không có gì xảy ra.
Martin Vegter

HISTTIMEFORMAT=/chỉ dành cho một lời mời đó historyđể có được một đầu ra như 123 /rm xkhi trích xuất cmd dễ dàng hơn. Có một vấn đề với một số phiên bản của bashnơi $HISTCMDlà không có thật trong bối cảnh đó, hãy thử các phiên bản mới.
Stéphane Chazelas

Vẫn không làm việc. Tôi tự hỏi, làm #trong mã không hoạt động như ý kiến ​​trong .bashrc?
Martin Vegter

1
@MartinVegter, vâng, đối với các mục lịch sử đã sửa đổi , bashchèn một số *sau lịch sử không được mong đợi. Nên sửa ngay.
Stéphane Chazelas

11

Tôi sẽ không trả lời chính xác câu hỏi của bạn, nhưng có thể cung cấp cho bạn một giải pháp thay thế cho vấn đề của bạn.

Nếu tôi hiểu chính xác bạn lo ngại về những lỗi bạn có thể mắc phải bằng cách gõ, ví dụ: !rmnếu điều đó xảy ra thì rmlệnh trước đó trong lịch sử sẽ loại bỏ thứ bạn muốn giữ.

Trong trường hợp này, một tùy chọn bash đẹp là histverify. Nếu bạn shopt -s histverifyvà nếu bạn nhớ lại một lệnh bằng tiếng nổ !, nó sẽ không thực thi ngay lập tức, nhưng được tải trong đường dẫn để bạn có thể quyết định thực hiện lệnh đó hay không, và điều này cũng cho bạn khả năng chỉnh sửa nó.

Thử nó:

  • Không có histverify:

    $ touch some_foo
    $ rm some_foo
    $ touch some_foo
    $ !rm
    rm some_foo
    $ # oooops in fact I'd've like to keep it this time
  • Với histverify:

    $ shopt -s histverify
    $ touch some_foo
    $ rm some_foo
    $ touch some_foo
    $ !rm
    $ rm some_foo <cursor here>

    Trong trường hợp này, bạn sẽ có con trỏ ở cuối dòng, sẵn sàng khởi chạy lại - hoặc không - hoặc chỉnh sửa nó.

Nếu bạn thích tùy chọn này, hãy đặt nó vào .bashrc:

shopt -s histverify
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.