Cara Menjebak Kesalahan dalam Skrip Bash di Linux
Diterbitkan: 2022-08-27Secara default, skrip Bash di Linux akan melaporkan kesalahan tetapi tetap berjalan. Kami menunjukkan kepada Anda bagaimana menangani kesalahan sendiri sehingga Anda dapat memutuskan apa yang perlu terjadi selanjutnya.
Penanganan Kesalahan dalam Skrip
Menangani kesalahan adalah bagian dari pemrograman. Bahkan jika Anda menulis kode tanpa cacat, Anda masih dapat mengalami kondisi kesalahan. Lingkungan di komputer Anda berubah seiring waktu, saat Anda menginstal dan menghapus instalan perangkat lunak, membuat direktori, dan melakukan peningkatan dan pembaruan.
Misalnya, skrip yang digunakan untuk berjalan tanpa masalah dapat mengalami kesulitan jika jalur direktori berubah, atau izin diubah pada file. Tindakan default shell Bash adalah mencetak pesan kesalahan dan terus menjalankan skrip. Ini adalah default yang berbahaya.
Jika tindakan yang gagal sangat penting untuk beberapa pemrosesan atau tindakan lain yang terjadi kemudian di skrip Anda, tindakan kritis itu tidak akan berhasil. Betapa berbahayanya itu, tergantung pada apa yang coba dilakukan skrip Anda.
Skema yang lebih kuat akan mendeteksi kesalahan dan membiarkan skrip bekerja jika perlu dimatikan atau mencoba memperbaiki kondisi kesalahan. Misalnya, jika direktori atau file tidak ada, mungkin cukup memuaskan jika skrip dibuat ulang.
Jika skrip mengalami masalah yang tidak dapat dipulihkan, skrip dapat dimatikan. Jika skrip harus dimatikan, skrip dapat memiliki kesempatan untuk melakukan pembersihan apa pun yang diperlukan, seperti menghapus file sementara atau menulis kondisi kesalahan dan alasan penonaktifan ke file log.
Mendeteksi Status Keluar
Perintah dan program menghasilkan nilai yang dikirim ke sistem operasi saat dihentikan. Ini disebut status keluar mereka. Ini memiliki nilai nol jika tidak ada kesalahan, atau nilai bukan nol jika terjadi kesalahan.
Kita dapat memeriksa status keluar—juga dikenal sebagai kode kembali—dari perintah yang digunakan skrip, dan menentukan apakah perintah itu berhasil atau tidak.
Di Bash, nol sama dengan benar. Jika respons dari perintah tidak benar, kami tahu ada masalah yang terjadi dan kami dapat mengambil tindakan yang tepat.
Salin skrip ini ke editor, dan simpan ke file bernama “bad_command.sh.”
#!/bin/bash jika ( ! bad_command ); kemudian echo "bad_command menandai kesalahan." keluar 1 fi
Anda harus membuat skrip dapat dieksekusi dengan perintah chmod
. Ini adalah langkah yang diperlukan untuk membuat skrip apa pun dapat dieksekusi, jadi jika Anda ingin mencoba skrip di mesin Anda sendiri, ingatlah untuk melakukan ini untuk masing-masing skrip. Ganti nama skrip yang sesuai dalam setiap kasus.
chmod +x bad_command.sh
Saat kami menjalankan skrip, kami melihat pesan kesalahan yang diharapkan.
./bad_command.sh
Tidak ada perintah seperti "bad_command", juga bukan nama fungsi di dalam skrip. Itu tidak dapat dieksekusi, jadi responsnya tidak nol. Jika responsnya bukan nol—tanda seru digunakan di sini sebagai operator NOT
logis—tubuh pernyataan if
dieksekusi.
Dalam skrip dunia nyata, ini dapat menghentikan skrip, yang dilakukan oleh contoh kita, atau dapat mencoba memperbaiki kondisi kesalahan.
Mungkin terlihat seperti jalur exit 1
berlebihan. Lagi pula, tidak ada yang lain dalam skrip dan itu akan tetap berakhir. Tetapi menggunakan perintah exit
memungkinkan kita untuk meneruskan status keluar kembali ke shell. Jika skrip kita dipanggil dari dalam skrip kedua, skrip kedua itu akan mengetahui bahwa skrip ini mengalami kesalahan.
Anda dapat menggunakan operator logika OR
dengan status keluar dari suatu perintah, dan memanggil perintah atau fungsi lain dalam skrip Anda jika ada respons bukan nol dari perintah pertama.
perintah_1 || perintah_2
Ini berfungsi karena perintah pertama berjalan OR
yang kedua. Perintah paling kiri dijalankan terlebih dahulu. Jika berhasil perintah kedua tidak dijalankan. Tetapi jika perintah pertama gagal, perintah kedua dijalankan. Jadi kita bisa menyusun kode seperti ini. Ini adalah "logis-or./sh."
#!/bin/bash kesalahan_penangan() { echo "Kesalahan: ($?) $1" keluar 1 } perintah_buruk || error_handler "bad_command gagal, Baris: ${LINENO}"
Kami telah mendefinisikan fungsi yang disebut error_handler
. Ini mencetak status keluar dari perintah yang gagal, disimpan dalam variabel $?
dan sebaris teks yang diteruskan ke sana saat fungsi dipanggil. Ini disimpan dalam variabel $1
. Fungsi mengakhiri skrip dengan status keluar satu.
Script mencoba menjalankan bad_command
yang jelas-jelas gagal, jadi perintah di sebelah kanan operator logika OR
, ||
, dieksekusi. Ini memanggil fungsi error_handler
dan meneruskan string yang menamai perintah yang gagal, dan berisi nomor baris dari perintah yang gagal.
Kami akan menjalankan skrip untuk melihat pesan penangan kesalahan, dan kemudian memeriksa status keluar skrip menggunakan echo.
./logis-or.sh
gema $?
Fungsi error_handler
kecil kami menyediakan status keluar dari upaya menjalankan bad_command
, nama perintah, dan nomor baris. Ini adalah informasi yang berguna saat Anda men-debug skrip.
Status keluar dari skrip adalah satu. Status keluar 127 yang dilaporkan oleh error_handler
berarti "perintah tidak ditemukan." Jika kita mau, kita bisa menggunakannya sebagai status keluar dari skrip dengan meneruskannya ke perintah exit
.
Pendekatan lain adalah memperluas error_handler
untuk memeriksa kemungkinan nilai yang berbeda dari status keluar dan untuk melakukan tindakan yang berbeda sesuai dengan itu, menggunakan jenis konstruksi ini:
kode_keluar=$? if [ $exit_code -eq 1 ]; kemudian echo "Operasi tidak diizinkan" elif [ $exit_code -eq 2 ]; kemudian echo "Penyalahgunaan shell bawaan" . . . elif [ $status -eq 128 ]; kemudian echo "Argumen tidak valid" fi
Menggunakan set Untuk Memaksa Keluar
Jika Anda tahu bahwa Anda ingin skrip Anda keluar setiap kali ada kesalahan, Anda dapat memaksanya untuk melakukannya. itu berarti Anda mengabaikan kemungkinan pembersihan—atau kerusakan lebih lanjut, juga—karena skrip Anda berhenti segera setelah mendeteksi kesalahan.
Untuk melakukan ini, gunakan perintah set
dengan opsi -e
(error). Ini memberitahu skrip untuk keluar setiap kali perintah gagal atau mengembalikan kode keluar lebih besar dari nol. Juga, menggunakan opsi -E
memastikan deteksi kesalahan dan perangkap berfungsi dalam fungsi shell.
Untuk juga menangkap variabel yang tidak diinisialisasi, tambahkan opsi -u
(tidak disetel). Untuk memastikan bahwa kesalahan terdeteksi dalam urutan pipa, tambahkan opsi -o pipefail
. Tanpa ini, status keluar dari urutan perintah yang disalurkan adalah status keluar dari perintah terakhir dalam urutan. Perintah yang gagal di tengah urutan pipa tidak akan terdeteksi. Opsi -o pipefail
harus ada dalam daftar opsi.
Urutan untuk ditambahkan ke bagian atas skrip Anda adalah:
set -Eeuo pipefail
Berikut adalah skrip pendek yang disebut "unset-var.sh", dengan variabel yang tidak disetel di dalamnya.
#!/bin/bash set -Eeou pipefail echo "$variabel_tidak disetel" echo "Apakah kita melihat baris ini?"
Ketika kami menjalankan skrip, unset_variable dikenali sebagai variabel yang tidak diinisialisasi dan skrip dihentikan.
./unset-var.sh
Perintah echo
kedua tidak pernah dieksekusi.
Menggunakan perangkap Dengan Kesalahan
Perintah Bash trap memungkinkan Anda menominasikan perintah atau fungsi yang harus dipanggil saat sinyal tertentu dinaikkan. Biasanya ini digunakan untuk menangkap sinyal seperti SIGINT
yang muncul saat Anda menekan kombinasi tombol Ctrl+C. Skrip ini adalah "sigint.sh."
#!/bin/bash trap "echo -e '\nDihentikan oleh Ctrl+c'; keluar" TANDA penghitung = 0 sementara benar melakukan echo "Nomor lingkaran:" $((++penghitung)) tidur 1 selesai
Perintah trap
berisi perintah echo
dan perintah exit
. Ini akan dipicu ketika SIGINT
dinaikkan. Sisa skrip adalah loop sederhana. Jika Anda menjalankan skrip dan menekan Ctrl+C, Anda akan melihat pesan dari definisi trap
, dan skrip akan berhenti.
./sigint.sh
Kita dapat menggunakan trap
dengan sinyal ERR
untuk menangkap kesalahan yang terjadi. Ini kemudian dapat diumpankan ke perintah atau fungsi. Ini adalah "trap.sh." Kami mengirimkan pemberitahuan kesalahan ke fungsi yang disebut error_handler
.
#!/bin/bash perangkap 'error_handler $? $LINENO' ERR error_handler() { echo "Kesalahan: ($1) terjadi pada $2" } utama() { echo "Di dalam fungsi utama ()" bad_command kedua ketiga keluar $? } kedua() { echo "Setelah panggilan ke main()" echo "Di dalam fungsi kedua ()" } ketiga() { echo "Di dalam fungsi ketiga ()" } utama
Sebagian besar skrip ada di dalam fungsi main
, yang memanggil fungsi second
dan third
. Ketika kesalahan ditemukan—dalam hal ini, karena bad_command
tidak ada—pernyataan trap
mengarahkan kesalahan ke fungsi error_handler
. Ini melewati status keluar dari perintah gagal dan nomor baris ke fungsi error_handler
.
./trap.sh
Fungsi error_handler
kami hanya mencantumkan detail kesalahan ke jendela terminal. Jika mau, Anda dapat menambahkan perintah exit
ke fungsi agar skrip dihentikan. Atau Anda dapat menggunakan serangkaian pernyataan if/elif/fi
untuk melakukan tindakan yang berbeda untuk kesalahan yang berbeda.
Dimungkinkan untuk memperbaiki beberapa kesalahan, yang lain mungkin mengharuskan skrip untuk berhenti.
Tip Terakhir
Menangkap kesalahan sering kali berarti mendahului hal-hal yang bisa salah, dan memasukkan kode untuk menangani kemungkinan itu jika muncul. Itu selain memastikan alur eksekusi dan logika internal skrip Anda benar.
Jika Anda menggunakan perintah ini untuk menjalankan skrip Anda, Bash akan menunjukkan kepada Anda keluaran jejak saat skrip dijalankan:
bash -x skrip Anda.sh
Bash menulis keluaran jejak di jendela terminal. Ini menunjukkan setiap perintah dengan argumennya—jika ada. Ini terjadi setelah perintah diperluas tetapi sebelum dieksekusi.
Ini bisa menjadi bantuan luar biasa dalam melacak bug yang sulit dipahami.
TERKAIT: Cara Memvalidasi Sintaks Skrip Bash Linux Sebelum Menjalankannya