- Saat skrip Bash berjalan tidak sesuai harapan, melacak penyebabnya jadi lebih mudah hanya dengan melihat perintah yang benar-benar dijalankan
set -xmenampilkan setiap baris setelah ekspansi variabel, sehingga Anda bisa memeriksa perintah apa yang sebenarnya dijalankan skrip- Menjalankannya dari baris perintah dengan
bash -x script.shmemberi efek yang sama seperti menambahkanset -xdi bagian atasscript.sh - Menggunakan trap
DEBUGbersamareadmemungkinkan Anda berhenti sebelum setiap baris dijalankan untuk memeriksa nama file, nomor baris, dan perintah berikutnya - Fungsi
die() { echo $1 >&2; exit 1; }menyederhanakan alur menampilkan pesan ke standard error lalu keluar setelah perintah gagal
Memeriksa alur eksekusi secara visual
set -xmenampilkan baris yang dijalankan skrip, dan variabel ditampilkan dengan nilainya yang sudah diekspansi- Anda bisa memakainya dengan menambahkan
set -xdi bagian atas skrip - Perilaku yang sama juga bisa dijalankan dari baris perintah
$ bash -x script.sh- Ini sama seperti menambahkan
set -xdi paling atasscript.sh
Berhenti dan memeriksa setiap baris
- trap
DEBUGdijalankan sebelum setiap baris kode dieksekusi - Jika Anda menambahkan kode berikut di awal skrip, skrip akan menunggu input Enter sebelum menjalankan perintah berikutnya
trap '(read -p "\[$BASH_SOURCE: $LINENO] $BASH_COMMAND")' DEBUGread -pmenampilkan pesan dan menunggu input Enter$BASH_SOURCEadalah nama file skrip$LINENOadalah nomor baris$BASH_COMMANDadalah perintah yang akan dijalankan berikutnya
Menampilkan pesan lalu keluar saat gagal
- Fungsi
diedapat digunakan untuk menampilkan pesan dan mengakhiri program saat perintah gagaldie() { echo $1 >&2; exit 1; }- Anda bisa menambahkannya setelah perintah yang dapat gagal, seperti
some_command || die "oh no!"
- Fungsi ini mengirim pesan ke standard error dan keluar dengan
exit 1
1 komentar
Pendapat Hacker News
Ada fungsi logging
zdebugdi berbagai bagian kode: https://github.com/zbm-dev/zfsbootmenu/blob/master/zfsbootme...Jika logging debug dinyalakan lalu menekan Ctrl-T dari menu utama, akan muncul tampilan seperti ini: https://i.imgur.com/Ge75zkP.png
Ada juga profiling flamegraph yang bisa diaktifkan lewat https://github.com/zbm-dev/zfsbootmenu/blob/master/zfsbootme..., dan jika data yang di-dump lewat port serial dirakit kembali, bisa dibuat grafik seperti https://raw.githubusercontent.com/zbm-dev/zfsbootmenu/master...
Bash ternyata fleksibel juga
set -x,PS4='+ ${BASH_SOURCE:-}:${FUNCNAME[0]:-}:L${LINENO:-}: 'sangat bergunaDengan ini, nama file, nama fungsi, dan nomor baris ditampilkan, sehingga cukup membantu saat men-debug skrip Bash besar
shellcheck. Meski tidak menemukan masalah secara langsung, ia memberi tahu potensi masalahSaya juga menyarankan menulis ulang skrip dengan bahasa lain. Di perusahaan, kami sedang mengganti skrip Bash ke Rust; biaya masuknya memang tinggi, tetapi kode akhirnya jauh lebih mudah dirawat dan lebih andal
Bash masih bagus untuk skrip cepat, tetapi kalau sudah melewati sekitar 100 baris, layak memakai bahasa yang memberi jaminan lebih kuat
die()adalah fungsi pembantu yang mencetak pesan kesalahan ke standard error lalu keluar dengan kode kesalahan yang ditentukanLebih banyak kode keluar skrip shell dan fungsi pembantu ada di sini: https://github.com/SixArm/unix-shell-script-kit/blob/main/un...
Namun saya agak kurang sreg dengan filosofi
dieitu. Fungsidiepada dasarnya seharusnya meneruskan kode keluar dari perintah yang gagal, dan tidak menyembunyikan output kesalahan dari perintah tersebutKalau dalam skrip besar saya ingin memberi makna sendiri pada kegagalan perintah, saya akan memakai
dieyang lebih khusus secara terpisah.diesaya kira-kira berbentuk__errex "$?" "${LINENO}" "$0", yang mencetak error fatal, nomor baris, nama skrip, dan pesan, lalu berakhir dengan kode keluar tersebutSalah satu contoh implementasinya ada di sini: https://github.com/TritonDataCenter/sdc-headnode/blob/master...
Jika dipakai seperti
some-command || fail "message", saatsome-commandmengembalikan status keluar bukan 0, ia akan membuat stack trace dan menghentikan shellJika ingin membuat stack trace di dalam fungsi lalu mengembalikannya, bisa memakai
some-command || softfail "message" || return $?Ia bisa melakukan hal yang dibutuhkan, tetapi kaku dan sintaksnya juga mengerikan. Begitu skrip mencapai ukuran atau kompleksitas tertentu, kita dipaksa memindahkannya ke bahasa yang benar-benar layak; mungkin itu memang desain yang disengaja
Di distro modern, umumnya ada versi Bash yang cukup baru, dan kalau tidak memakai hal seperti array, versi juga tidak terlalu perlu dipikirkan
Daya tarik Bash ada pada posisinya di antara bahasa dan tool lain. Ia ideal untuk merangkai tool lain, cukup dekat dengan sistem operasi sehingga nyaman, dan tidak menuntut instalasi library seperti Python
Untuk scripting yang lebih kompleks, orang sering menyarankan pindah ke bahasa seperti Python, tetapi itu menambahkan lapisan kompleksitas yang dalam jangka panjang bisa jadi tidak membantu. Skrip Bash yang ditulis 20 tahun lalu masih berjalan baik, sedangkan program Python dari 20 tahun lalu kemungkinan besar mengalami masalah versi
rcdari Plan 9 memang lebih rapi, tetapi tidak ada yang akan pindah hanya karena “mirip tapi lebih rapi”. Saat ini juga Anda bisa memasang sesuatu yang mirip tetapi lebih baik dari https://pkgsrc.se/shells, tetapi orang tetap tidak memakainya, dan cara menjalankannya bagi orang lain pun tidak berubahUntuk menggantikan teknologi yang sudah mapan, ia harus beberapa kali lipat lebih baik dalam aspek-aspek inti. Plan 9 juga lebih baik daripada keluarga UNIX, tetapi tidak cukup baik untuk menggantikannya
Sulit membuat sesuatu yang cukup baik untuk menggantikan ceruk scripting shell Bourne. Sebelum menjadi sebaik itu, ia sudah masuk ke posisi ekologis atau wilayah masalah bahasa scripting sungguhan seperti Perl, Python, atau Ruby
Dalam wilayah masalah yang sempit, optimum lokal menyedot semua udara, sehingga sulit bagi pesaing yang mendekati optimum global teoretis untuk muncul
Fitur-fitur baru belakangan ini memang cukup baik ditumpangkan di atas
sh/Bash, tetapi pada akhirnya scripting shell hanyalah sarana untuk mencapai tujuan, dan harus berevolusi jauh lebih lambat dibanding bahasa pemrograman umumCiri inti Bash/
shadalah sifatnya yang anti-entropi. Karena hampir tidak ada pengembangan atau evolusi, kecil kemungkinan kita dibuat pusing oleh dependensi atau fitur baru, dan hal-hal yang berfungsi 20 tahun lalu tetap menjadi tool dasarSecara desain, ini menjadi sistem yang menolak perubahan, dan ketika orang mentok pada batasannya, muncul insentif untuk keluar dari situ
Sebagian besar skrip FreeBSD ditulis untuk
sh, dan karenashadalah bagian dari standar POSIX, rasanya dukungannya jauh lebih luas. Menurut saya Bash hanya termasuk populerNamun karena Bash terlalu buruk, saya sampai membuat banyak utilitas dengan namespace yang dipersempit agar bisa memakai skrip Groovy. Bisa dikembangkan dengan IDE, sistem pustakanya juga aman, dan Groovy merapikan hampir semua ketidaknyamanan Java, jadi jauh lebih baik
Ada beberapa keterbatasan, tetapi secara umum bisa berguna: https://github.com/ketancmaheshwari/pd
die()bagus, tetapi Bash punya sifat yang menyebalkan. Jika mencoba melakukanexitdi dalam subshell, yang berhenti hanya subshell itu, sementara sisa skrip tetap berjalanMisalnya, jika memanggil
diedi dalam pipeline seperticat myfile | while read line; do ... die "Found match" ... done,echo "I don't want this line"setelahnya tetap akan tercetakSering kali subshell bisa dihindari, dan pada contoh ini
shellcheckmemang tepat menunjuk UUOC; memperbaikinya juga menyelesaikan masalahdiedi dalam subshellNamun kadang subshell tidak bisa dihindari, atau menghindarinya membuat skrip terlalu rumit. Dalam kasus seperti itu, Anda bisa menyimpan PID di awal skrip dengan
MYPID=$$, lalu mematikannya sepertidie() { echo "$1" >&2; kill -9 $MYPID; exit 1; }Tentu ini juga kompromi. Cara mematikan seperti ini cukup kasar, dan entah kenapa juga tidak sepenuhnya dapat diandalkan
set -esaja sudah membuat skrip ikut berhenti ketika subshell keluar dengan kode error bukan 0Saya sulit membayangkan alasan untuk tidak memakai
set -edalam skrip shell apa punset -euxo pipefailPengujian kondisi memang jadi sedikit lebih sulit, tetapi terutama
pipefailsaja sudah berkali-kali membayar dirinyaset +xKalau terus dinyalakan, cukup membosankan
Namun
-xsaya simpan sampai benar-benar perlu melihat semua output debug yang berantakan