Bagaimana cara menyimpan riwayat terminal ke file dari file bash?

7

Saya mencoba membuat skrip bash yang akan menyimpan histori terminal ke file bernama hist.txt. Penggunaan history > hist.txttampaknya tidak berfungsi di skrip bash, tetapi berfungsi dengan baik saat dieksekusi di baris perintah.

Bimbingan apa pun sangat dihargai.

Judy terima kasih

Judy
sumber
3
Pertanyaan Anda agak membingungkan. Apa yang Anda maksud dengan "tampaknya tidak berfungsi di file bash, tetapi berfungsi dengan baik ketika dieksekusi di baris perintah"? Apakah maksud Anda Anda mencoba menyimpan riwayat perintah dari dalam skrip bash yang sedang dijalankan? Seperti Anda ingin menyimpan perintah apa yang telah dieksekusi oleh skrip? Script itu sendiri adalah sejarah dalam hal ini.
Stephen
6
Atau apakah Anda ingin menampilkan riwayat bash pengguna tertentu? Anda bisa membaca file pengguna ~/.bash_history.
Arronical
1
@Arronical note bahwa ini hanya akan berfungsi jika pengguna menggunakan Bash sebagai shell mereka, yang tidak selalu demikian.
1
@ p0llard Tentu saja, saya melompat dengan asumsi bahwa seperti itu dalam skrip Bash, itu akan menjadi Bash sebagai shell pengguna, tapi itu mungkin tidak terjadi, seperti yang Anda katakan. Detail dan latar belakang yang bagus dalam jawaban Anda, BTW.
Arronical

Jawaban:

11

Jawaban singkat

Jalankan skrip dengan sourceatau .:

source ./script_name.sh

atau

. ./script_name.sh

Yang terakhir ini sedikit lebih kompatibel di berbagai shell.

Jawaban panjang

Pertanyaan ini menyoroti poin penting, yaitu skrip shell dijalankan dalam konteksnya sendiri. Untuk melihat apa artinya ini, pertimbangkan skrip shell berikut:

#!/bin/bash

cd /
ls

Jika Anda menjalankan ini, Anda akan mendapatkan hasil seperti ini:

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

Tetapi Anda akan melihat bahwa setelah Anda menjalankan skrip, Anda masih berada di direktori apa pun Anda berada sebelum menjalankannya: bagian cd /dalam skrip tidak benar-benar memengaruhi sesi Anda - itu hanya memengaruhi konteks tempat skrip dijalankan, yang dibuat untuk menjalankan skrip, dan dihancurkan begitu kembali.

The sourceperintah akan 'membaca dan menjalankan perintah dari argumen nama file di shell saat ini konteks', sehingga setiap perintah seperti cddi dalamnya akan mempengaruhi sesi Anda saat ini. Jika Anda menjalankan skrip di atas dengan mengirimkannya kepada sourceAnda, Anda akan menemukan bahwa Anda berakhir di dalam direktori root setelah dijalankan.

Dalam kasus ini, masalahnya adalah bahwa historyperintah tersebut memberi Anda sejarah untuk konteks shell saat ini; konteks shell yang dijalankan skrip Anda tanpa menggunakan sourcetidak memiliki riwayat, sehingga skrip tidak menulis apa pun ke file output. Jika Anda menggunakannya sourceakan mengeksekusi dalam konteks yang benar, dan akan berfungsi seperti yang diharapkan.

NB: sourceadalah built-in shell, bukan program per se - di Bash, sourceidentik dengan ., tetapi dalam beberapa shell hanya .akan bekerja - Saya telah menggunakan sourcejawaban ini karena lebih mudah dibaca daripada ., tetapi untuk kompatibilitas maksimum, .harus digunakan.


sumber
Sangat menarik dibaca. Saya selalu bertanya-tanya tentang perintah sejarah 'hilang', sekarang saya tahu mengapa. Terima kasih!
Tico
10

Pertama-tama, perhatikan bahwa riwayat Anda sudah ada dalam file. Jika Anda menjalankan bash, biasanya namanya ~/.bash_history. Lebih khusus, itu adalah apa pun yang Anda atur variabelnya HISTFILE. Jika Anda ingin menyalinnya ke file lain, jalankan sajacat "$HISTFILE" > hist.txt

Sekarang, mengapa historyperintah tidak bekerja dalam skrip bash shell, itu karena skrip dijalankan dalam cangkang anak non-interaktif dari sesi shell Anda saat ini. Kerang anak tidak mewarisi semua lingkungan induk (jadi tidak semua variabel yang ditetapkan), hanya variabel yang telah diekspor. Untuk menggambarkan, skrip di bawah ini akan menggemakan nilai variabel $var:

#!/bin/bash
echo "$var"

Sekarang, atur $varsesuatu dan jalankan skrip:

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

Selanjutnya, ekspor variabel terlebih dahulu:

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

Seperti yang Anda lihat, ketika variabel telah diekspor, itu tersedia untuk shell anak.

Seperti yang saya sebutkan sebelumnya, riwayat disimpan dalam file yang ditunjukkan oleh variabel $HISTFILENAME. Karena itu tidak diekspor secara default, itu tidak disetel saat menjalankan skrip:

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

Seperti yang Anda lihat dalam contoh di atas, variabel HISTFILEdiatur dalam sesi shell normal saya, tetapi kosong saat menjalankan skrip.

Jadi, untuk mendapatkan riwayatnya, Anda memiliki beberapa opsi:

  1. Nilai standarnya HISTFILEadalah $HOME/.bash_history. Jika Anda belum mengubahnya, Anda bisa menjalankan perintah ini di skrip Anda:

    cat "$HOME/.bash_history" > history
  2. Anda bisa meneruskan $HISTFILEvariabel ke skrip Anda dan catitu:

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

    Simpan di atas sebagai foo.shdan jalankan seperti ini:

    ./foo.sh "$HISTORY"
  3. Pastikan variabel diekspor. Tambahkan baris ini ke file Anda ~/.bash_profile(jika ada) atau ~/.profile(jika ~/.bash_profiletidak ada):

    export HISTFILE

    Kemudian, keluar dan masuk kembali dan Anda harus dapat lari history > hist.txtdari skrip seperti yang diharapkan. Ini karena export VARberarti "sediakan $ VAR untuk kulit anak". Dalam istilah praktis, ini berarti bahwa nilai HISTFILEakan diwarisi oleh shell non-interaktif yang Anda gunakan untuk menjalankan skrip Anda.

    Sekarang, sementara HISTFILEakan diatur, itu belum dibaca oleh shell menjalankan skrip. Jadi, untuk membuatnya bekerja, Anda harus membacanya history -rterlebih dahulu. Seluruh skrip akan terlihat seperti ini:

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

    Atau, cukup ekspor secara manual sebelum menjalankan skrip:

    $ export HISTFILE

    Tapi Anda masih harus melakukannya history -rdi skrip.

  4. Anda dapat sourcemelakukannya seperti yang disarankan oleh jawaban @ p0llard .

terdon
sumber