GNU/Linux >> Belajar Linux >  >> Linux

Naikkan kesalahan dalam skrip Bash

Ada beberapa cara lagi untuk mendekati masalah ini. Dengan asumsi salah satu kebutuhan Anda adalah menjalankan skrip/fungsi shell yang berisi beberapa perintah shell dan memeriksa apakah skrip berjalan dengan sukses dan membuang kesalahan jika terjadi kegagalan.

Perintah shell pada umumnya mengandalkan kode keluar yang dikembalikan untuk memberi tahu shell jika berhasil atau gagal karena beberapa kejadian yang tidak terduga.

Jadi apa yang ingin Anda lakukan termasuk dalam dua kategori ini

  • keluar jika ada kesalahan
  • keluar dan bersihkan kesalahan

Bergantung pada yang mana yang ingin Anda lakukan, ada opsi shell yang tersedia untuk digunakan. Untuk kasus pertama, shell menyediakan opsi dengan set -e dan untuk yang kedua Anda bisa melakukan trap pada EXIT

Haruskah saya menggunakan exit dalam skrip/fungsi saya?

Menggunakan exit umumnya meningkatkan keterbacaan Dalam rutinitas tertentu, setelah Anda mengetahui jawabannya, Anda ingin segera keluar ke rutinitas pemanggilan. Jika rutin didefinisikan sedemikian rupa sehingga tidak memerlukan pembersihan lebih lanjut setelah mendeteksi kesalahan, tidak segera keluar berarti Anda harus menulis lebih banyak kode.

Jadi jika Anda perlu melakukan tindakan pembersihan pada skrip untuk membuat penghentian skrip menjadi bersih, sebaiknya tidak untuk menggunakan exit .

Haruskah saya menggunakan set -e untuk kesalahan saat keluar?

Tidak!

set -e adalah upaya untuk menambahkan "deteksi kesalahan otomatis" ke shell. Tujuannya adalah untuk menyebabkan shell dibatalkan setiap kali terjadi kesalahan, tetapi ia datang dengan banyak potensi jebakan misalnya,

  • Perintah yang merupakan bagian dari tes if kebal. Dalam contoh, jika Anda mengharapkannya rusak pada test periksa direktori yang tidak ada, itu tidak akan, itu menuju ke kondisi lain

    set -e
    f() { test -d nosuchdir && echo no dir; }
    f
    echo survived
    
  • Perintah dalam pipa selain yang terakhir, kebal. Pada contoh di bawah ini, karena kode keluar perintah yang terakhir dieksekusi (paling kanan) dianggap ( cat ) dan berhasil. Hal ini dapat dihindari dengan menyetelnya dengan set -o pipefail opsi tetapi masih peringatan.

    set -e
    somecommand that fails | cat -
    echo survived 
    

Direkomendasikan untuk digunakan - trap saat keluar

Putusannya adalah jika Anda ingin dapat menangani kesalahan alih-alih keluar secara membabi buta, alih-alih menggunakan set -e , gunakan trap pada ERR sinyal semu.

ERR trap bukan untuk menjalankan kode ketika shell itu sendiri keluar dengan kode kesalahan bukan nol, tetapi ketika ada perintah yang dijalankan oleh shell itu yang bukan bagian dari suatu kondisi (seperti di if cmd , atau cmd || ) keluar dengan status keluar bukan nol.

Praktik umum adalah kami mendefinisikan penangan jebakan untuk memberikan informasi debug tambahan di baris mana dan apa yang menyebabkan keluarnya. Ingat kode keluar dari perintah terakhir yang menyebabkan ERR sinyal akan tetap tersedia pada saat ini.

cleanup() {
    exitcode=$?
    printf 'error condition hit\n' 1>&2
    printf 'exit code returned: %s\n' "$exitcode"
    printf 'the command executing at the time of the error was: %s\n' "$BASH_COMMAND"
    printf 'command present on line: %d' "${BASH_LINENO[0]}"
    # Some more clean up code can be added here before exiting
    exit $exitcode
}

dan kami hanya menggunakan penangan ini seperti di bawah ini di atas skrip yang gagal

trap cleanup ERR

Menyatukan ini pada skrip sederhana yang berisi false pada baris 15, informasi yang akan Anda dapatkan sebagai

error condition hit
exit code returned: 1
the command executing at the time of the error was: false
command present on line: 15

trap juga menyediakan opsi terlepas dari kesalahan untuk hanya menjalankan pembersihan pada penyelesaian shell (misalnya skrip shell Anda keluar), pada sinyal EXIT . Anda juga bisa menjebak beberapa sinyal sekaligus. Daftar sinyal yang didukung untuk dijebak dapat ditemukan di trap.1p - halaman manual Linux

Hal lain yang perlu diperhatikan adalah memahami bahwa tidak ada metode yang disediakan berfungsi jika Anda berurusan dengan sub-shell yang terlibat dalam hal ini, Anda mungkin perlu menambahkan penanganan kesalahan Anda sendiri.

  • Pada sub-kulit dengan set -e tidak akan berhasil. false terbatas pada sub-shell dan tidak pernah disebarkan ke shell induk. Untuk melakukan penanganan error di sini, tambahkan logika Anda sendiri untuk melakukan (false) || false

    set -e
    (false)
    echo survived
    
  • Hal yang sama terjadi dengan trap juga. Logika di bawah ini tidak akan berfungsi karena alasan yang disebutkan di atas.

    trap 'echo error' ERR
    (false)
    

Penanganan error dasar

Jika runner kasus pengujian mengembalikan kode bukan nol untuk pengujian yang gagal, Anda cukup menulis:

test_handler test_case_x; test_result=$?
if ((test_result != 0)); then
  printf '%s\n' "Test case x failed" >&2  # write error message to stderr
  exit 1                                  # or exit $test_result
fi

Atau bahkan lebih singkat:

if ! test_handler test_case_x; then
  printf '%s\n' "Test case x failed" >&2
  exit 1
fi

Atau yang terpendek:

test_handler test_case_x || { printf '%s\n' "Test case x failed" >&2; exit 1; }

Untuk keluar dengan kode keluar test_handler:

test_handler test_case_x || { ec=$?; printf '%s\n' "Test case x failed" >&2; exit $ec; }

Penanganan error lanjutan

Jika Anda ingin mengambil pendekatan yang lebih komprehensif, Anda dapat memiliki penangan kesalahan:

exit_if_error() {
  local exit_code=$1
  shift
  [[ $exit_code ]] &&               # do nothing if no error code passed
    ((exit_code != 0)) && {         # do nothing if error code is 0
      printf 'ERROR: %s\n' "[email protected]" >&2 # we can use better logging here
      exit "$exit_code"             # we could also check to make sure
                                    # error code is numeric when passed
    }
}

kemudian aktifkan setelah menjalankan test case Anda:

run_test_case test_case_x
exit_if_error $? "Test case x failed"

atau

run_test_case test_case_x || exit_if_error $? "Test case x failed"

Keuntungan memiliki penangan kesalahan seperti exit_if_error adalah:

  • kami dapat membakukan semua logika penanganan error seperti logging, mencetak pelacakan tumpukan, notifikasi, melakukan pembersihan, dll., di satu tempat
  • dengan membuat penangan kesalahan mendapatkan kode kesalahan sebagai argumen, kita dapat menghindarkan penelepon dari kekacauan if memblokir yang menguji kode keluar untuk kesalahan
  • jika kita memiliki penangan sinyal (menggunakan trap), kita dapat memanggil penangan kesalahan dari sana

Penanganan kesalahan dan pustaka logging

Berikut adalah implementasi lengkap dari penanganan kesalahan dan logging:

https://github.com/codeforester/base/blob/master/lib/stdlib.sh

Postingan terkait

  • Penanganan kesalahan di Bash
  • Perintah bawaan 'penelepon' di Bash Hackers Wiki
  • Apakah ada kode status keluar standar di Linux?
  • BashFAQ/105 - Mengapa set -e (atau set -o errexit, atau trap ERR) tidak melakukan apa yang saya harapkan?
  • Setara dengan __FILE__ , __LINE__ di Bash
  • Apakah ada perintah TRY CATCH di Bash
  • Untuk menambahkan pelacakan tumpukan ke penangan kesalahan, Anda mungkin ingin melihat posting ini:Jejak program yang dijalankan yang dipanggil oleh skrip Bash
  • Mengabaikan kesalahan tertentu dalam skrip shell
  • Menangkap kode kesalahan dalam pipa shell
  • Bagaimana cara mengelola verbositas log di dalam skrip shell?
  • Bagaimana cara mencatat nama fungsi dan nomor baris di Bash?
  • Apakah tanda kurung siku ganda [[ ]] lebih disukai daripada tanda kurung siku tunggal [ ] di Bash?

Ini tergantung di mana Anda ingin pesan kesalahan disimpan.

Anda dapat melakukan hal berikut:

echo "Error!" > logfile.log
exit 125

Atau yang berikut ini:

echo "Error!" 1>&2
exit 64

Saat Anda mengajukan pengecualian, Anda menghentikan eksekusi program.

Anda juga dapat menggunakan sesuatu seperti exit xxx di mana xxx adalah kode kesalahan yang mungkin ingin Anda kembalikan ke sistem operasi (dari 0 hingga 255). Ini 125 dan 64 hanyalah kode acak yang dapat Anda gunakan untuk keluar. Saat Anda perlu memberi tahu OS bahwa program berhenti secara tidak normal (mis. terjadi kesalahan), Anda harus memberikan kode keluar bukan nol ke exit .

Seperti yang ditunjukkan oleh @chepner, Anda dapat melakukan exit 1 , yang berarti kesalahan yang tidak ditentukan .


Linux
  1. Penanganan kesalahan dalam skrip Bash

  2. Pelajari penanganan kesalahan Bash dengan contoh

  3. Script Bash Untuk Mengisi Template?

  1. Mengapa Skrip Bash Tidak Keluar Setelah Eksekusi?

  2. Kesalahan Skrip Bash:Ekspresi Integer Diharapkan?

  3. Cara Memisahkan String dalam Skrip Bash

  1. Jalankan skrip bash dari URL

  2. alternatif --config Java bash script

  3. nama dasar dengan spasi dalam skrip bash?