Simpan hanya perintah yang berhasil dalam sejarah BASH

20

Terkadang saya salah paham sintaksis sebuah perintah:

# mysql -d test
mysql: unknown option '-d'
# echo $?
2

Saya mencoba lagi dan melakukannya dengan benar:

# mysql --database test
Welcome to the MySQL monitor.
mysql >
...

Bagaimana saya mencegah perintah pertama, dengan kode kesalahan berbeda dari 0, untuk memasukkan sejarah?

Adam Matan
sumber

Jawaban:

20

Saya tidak berpikir Anda benar-benar menginginkan itu. Alur kerja saya yang biasa berjalan seperti ini:

  • Ketikkan perintah
  • Menjalankannya
  • Perhatikan itu gagal
  • Tekan tombol ATAS
  • Edit perintah
  • Jalankan lagi

Sekarang, jika perintah gagal tidak disimpan ke dalam sejarah saya tidak bisa dengan mudah kembali untuk memperbaiki dan menjalankannya lagi.

Rene Saarsoo
sumber
3
Saya kira desain yang lebih baik adalah riwayat sesi dan sejarah permanen. Terima kasih!
Adam Matan
Histori akan disimpan saat Anda keluar dari terminal. Jadi, sementara Anda bisa kembali ke perintah yang Anda ketikkan dalam sesi terminal ini, ia sebenarnya disimpan ke bash history saat keluar dari terminal.
Untuk Dilakukan
11

Satu-satunya cara saya bisa memikirkan untuk melakukan hal ini akan menggunakan history -ddi $PROMPT_COMMAND. Masalah dengan pendekatan ini atau apa pun adalah bahwa tidak mungkin untuk mengetahui apakah suatu perintah keluar dengan kesalahan atau berhasil diselesaikan dengan kode keluar yang tidak nol.

$ grep non_existent_string from_file_that_exists
$ echo $?
1
Dijeda sampai pemberitahuan lebih lanjut.
sumber
4

Sangat baik untuk memiliki komentar yang salah terakhir untuk memperbaikinya, tetapi segera setelah itu, itu berpotensi menjadi sampah yang membingungkan.

Pendekatan saya adalah dua langkah: menyimpan perintah yang gagal ketika mereka lakukan, dan menghapusnya beberapa saat kemudian.

Menyimpan perintah yang gagal saat melakukannya:

error_handler() {
    FAILED_COMMANDS="$(history | tail -1l | cut -c -5) $FAILED_COMMANDS"
}

trap error_handler ERR

trap command signalsdijalankan commandketika salah satu dari signals"dibangkitkan".

$(command), menjalankan commanddan menangkap hasilnya.

Ketika perintah gagal, potongan kode ini menangkap nomor sejarah dari perintah terakhir yang disimpan ke dalam sejarah , dan menyimpannya dalam variabel untuk dihapus di masa depan.

Sederhana, tetapi bekerja secara tidak benar dengan HISTCONTROLdan HISTIGNORE- ketika perintah tidak disimpan ke dalam riwayat karena salah satu variabel, jumlah riwayat dari perintah terakhir yang disimpan ke dalam sejarah adalah perintah sebelumnya; jadi, jika perintah yang salah tidak disimpan ke dalam riwayat, perintah sebelumnya akan dihapus.

Versi yang sedikit lebih rumit, yang berfungsi dengan benar dalam hal ini:

debug_handler() {
    LAST_COMMAND=$BASH_COMMAND;
}

error_handler() {
    local LAST_HISTORY_ENTRY=$(history | tail -1l)

    # if last command is in history (HISTCONTROL, HISTIGNORE)...
    if [ "$LAST_COMMAND" == "$(cut -d ' ' -f 2- <<< $LAST_HISTORY_ENTRY)" ]
    then
        # ...prepend it's history number into FAILED_COMMANDS,
        # marking the command for deletion.
        FAILED_COMMANDS="$(cut -d ' ' -f 1 <<< $LAST_HISTORY_ENTRY) $FAILED_COMMANDS"
    fi
}

trap error_handler ERR
trap debug_handler DEBUG

Hapus perintah yang disimpan beberapa saat kemudian:

exit_handler() {
    for i in $(echo $FAILED_COMMANDS | tr ' ' '\n' | uniq)
    do
        history -d $i
    done
    FAILED_COMMANDS=
}

trap exit_handler EXIT

Penjelasan:

Saat keluar dari Bash, untuk setiap nomor riwayat unik hapus entri riwayat yang sesuai,
lalu hapus FAILED_COMMANDSuntuk tidak menghapus perintah yang mewarisi nomor riwayat dari perintah yang sudah dihapus.

Jika Anda yakin itu FAILED_COMMANDSakan bebas dari duplikat, Anda dapat melakukannya dengan sederhana
(mis. Menulis for i in $FAILED_COMMANDS). Namun, jika Anda mengharapkannya tidak diurutkan dari yang terbesar ke yang terkecil (dalam hal ini selalu demikian), ganti uniqdengan sort -rnu.

Nomor histori di FAILED_COMMANDSharus unik dan diurutkan dari yang terbesar ke yang terkecil, karena ketika Anda menghapus entri, nomor perintah selanjutnya digeser - yaitu. saat Anda mengeluarkan history -d 2, entri ke-3 menjadi ke-2, ke-4 menjadi ke-3, dll.

Karena itu, ketika menggunakan kode ini, Anda tidak dapat secara manual memanggil di history -d <n>
mana nlebih kecil atau sama dengan jumlah terbesar yang tersimpanFAILED_COMMANDS
dan berharap kode tersebut berfungsi dengan baik.

Ini mungkin ide yang baik untuk menghubungkan exit_handlerdi EXIT, tetapi Anda juga dapat menghubungi kapan saja sebelumnya.

GingerPlusPlus
sumber