Làm cách nào để lưu lịch sử thiết bị đầu cuối vào một tệp từ tệp bash?


7

Tôi đang cố gắng tạo một tập lệnh bash sẽ lưu lịch sử thiết bị đầu cuối vào một tệp có tên là hist.txt. Việc sử dụng history > hist.txtdường như không hoạt động trong tập lệnh bash, nhưng hoạt động tốt khi được thực thi trong dòng lệnh.

Bất kỳ hướng dẫn được đánh giá rất cao.

Cảm ơn bạn


3
Câu hỏi của bạn hơi khó hiểu. Ý bạn là gì khi "dường như không hoạt động trong tệp bash, nhưng hoạt động tốt khi được thực thi trong dòng lệnh"? Bạn có nghĩa là bạn đang cố lưu lịch sử lệnh của bạn từ trong tập lệnh bash đang thực thi? Như bạn muốn lưu những lệnh nào đã được thực thi bởi tập lệnh? Kịch bản chính nó là một lịch sử trong trường hợp này.
Stephen

6
Hay bạn muốn xuất lịch sử bash của một người dùng cụ thể? Bạn chỉ có thể đọc ~/.bash_historytệp của người dùng .
Arronical

1
@Arronical lưu ý rằng điều này sẽ chỉ hoạt động nếu người dùng đang sử dụng Bash làm vỏ của họ, điều này không phải lúc nào cũng đúng.

1
@ p0llard Tất nhiên, tôi đã đưa ra giả định rằng như trong kịch bản Bash, nó sẽ là Bash như vỏ của người dùng, nhưng đó có thể không phải là trường hợp, như bạn đã nói. Chi tiết tốt và nền tảng trong câu trả lời của bạn BTW.
Arronical

Câu trả lời:


11

Câu trả lời ngắn

Chạy tập lệnh với sourcehoặc .:

source ./script_name.sh

hoặc là

. ./script_name.sh

Thứ hai là tương thích hơn một chút trên các vỏ khác nhau.

Câu trả lời dài

Câu hỏi này nêu bật một điểm quan trọng, đó là các kịch bản shell được chạy trong ngữ cảnh của riêng chúng. Để xem điều này có nghĩa là gì, hãy xem xét kịch bản shell sau:

#!/bin/bash

cd /
ls

Nếu bạn chạy cái này, bạn sẽ nhận được một đầu ra giống như thế này:

bin  boot  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

Nhưng bạn sẽ nhận thấy rằng sau khi bạn chạy tập lệnh, bạn vẫn ở trong bất kỳ thư mục nào bạn đã ở trước khi bạn chạy cd /tập lệnh : bên trong tập lệnh không thực sự ảnh hưởng đến phiên của bạn - nó chỉ ảnh hưởng đến bối cảnh mà tập lệnh đang chạy. được tạo cho tập lệnh chạy vào và bị hủy khi nó trả về.

Các sourcelệnh sẽ 'đọc và thực hiện các lệnh từ đối số tên tập tin trong bối cảnh hiện nay vỏ', vì vậy bất kỳ lệnh như cdbên trong nó sẽ ảnh hưởng đến phiên hiện tại của bạn. Nếu bạn đã chạy tập lệnh ở trên bằng cách chuyển nó cho sourcebạn, bạn sẽ thấy rằng bạn kết thúc bên trong thư mục gốc sau khi nó chạy.

Trong trường hợp này, vấn đề là historylệnh cung cấp cho bạn lịch sử cho bối cảnh shell hiện tại; bối cảnh shell mà tập lệnh của bạn chạy trong mà không sử dụng sourcekhông có lịch sử, vì vậy nó không ghi bất cứ điều gì vào tệp đầu ra. Nếu bạn sử dụng sourcenó sẽ thực thi trong ngữ cảnh chính xác và sẽ hoạt động như mong đợi.

NB: sourcelà một shell được tích hợp sẵn, không phải là chương trình mỗi lần - trong Bash, sourceđồng nghĩa với ., nhưng trong một số shell chỉ .hoạt động - Tôi đã sử dụng sourcetrong câu trả lời này vì nó dễ đọc hơn ., nhưng để tương thích tối đa, .nên được dùng.


Đọc rất thú vị. Tôi đã luôn tự hỏi về các lệnh lịch sử 'mất tích', bây giờ tôi biết tại sao. Cảm ơn!
Tico

10

Trước hết, lưu ý rằng lịch sử của bạn đã có trong một tệp. Nếu bạn đang chạy bash, tên của nó thường là ~/.bash_history. Cụ thể hơn, đó là bất cứ điều gì bạn đã đặt biến HISTFILE. Nếu bạn muốn sao chép nó sang tập tin khác, chỉ cần chạycat "$HISTFILE" > hist.txt

Bây giờ, về lý do tại sao historylệnh không hoạt động trong tập lệnh bash shell, đó là vì tập lệnh được chạy trong trình bao con không tương tác của phiên shell hiện tại của bạn. Các shell con không kế thừa tất cả môi trường của cha mẹ (vì vậy không phải tất cả các biến đã đặt), chỉ các biến đã được xuất. Để minh họa, đoạn script dưới đây sẽ lặp lại giá trị của biến $var:

#!/bin/bash
echo "$var"

Bây giờ, đặt $varthành một cái gì đó và chạy tập lệnh:

$ var="foo"
$ foo.sh
VAR: 

Tiếp theo, xuất biến đầu tiên:

$ var="foo"
$ export var
$ foo.sh
VAR: foo

Như bạn có thể thấy, khi biến đã được xuất, nó có sẵn cho các shell con.

Như tôi đã đề cập trước đó, lịch sử được lưu trữ trong tệp được chỉ ra bởi biến $HISTFILENAME. Vì không được xuất theo mặc định, nên nó không được đặt khi chạy tập lệnh:

$ cat foo.sh
#!/bin/bash
echo "HISTFILE: $HISTFILE"
$ ./foo.sh
HISTFILE:
$ echo $HISTFILE
/home/terdon/.bash_history

Như bạn có thể thấy trong ví dụ trên, biến HISTFILEđược đặt trong phiên shell thông thường của tôi, nhưng trống khi chạy tập lệnh.

Vì vậy, để có được lịch sử, bạn có một vài lựa chọn:

  1. HISTFILEGiá trị mặc định là $HOME/.bash_history. Nếu bạn không thay đổi điều đó, bạn chỉ cần chạy lệnh này trong tập lệnh của mình:

    cat "$HOME/.bash_history" > history
  2. Bạn có thể truyền $HISTFILEbiến cho tập lệnh của mình và catđó:

    #!/bin/bash
    cat "$1" > history

    Lưu ở trên foo.shvà chạy như thế này:

    ./foo.sh "$HISTORY"
  3. Hãy chắc chắn rằng biến được xuất. Thêm dòng này vào ~/.bash_profiletệp của bạn (nếu nó tồn tại) hoặc ~/.profile(nếu ~/.bash_profilekhông tồn tại):

    export HISTFILE

    Sau đó, đăng xuất và đăng nhập lại và bạn sẽ có thể chạy history > hist.txttừ một tập lệnh như mong đợi. Điều này là do export VARcó nghĩa là "cung cấp $ VAR cho vỏ con". Trong điều kiện thực tế, điều này có nghĩa là giá trị của HISTFILEsẽ được kế thừa bởi trình bao không tương tác mà bạn sử dụng để chạy tập lệnh của mình.

    Bây giờ, trong khi HISTFILEsẽ được thiết lập, nó đã không được đọc bởi shell đang chạy tập lệnh. Vì vậy, để làm cho nó hoạt động, trước tiên bạn cần đọc nó history -r. Toàn bộ kịch bản sẽ như thế này:

    $!/bin/bash
    history -r
    history > hist.txt

    Ngoài ra, chỉ cần xuất thủ công trước khi chạy tập lệnh:

    $ export HISTFILE

    Nhưng bạn vẫn sẽ cần history -rtrong kịch bản.

  4. Bạn có thể sourcelàm như được đề xuất bởi câu trả lời của @ p0llard .

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.