Setiap perintah yang berakhir selalu menyisakan satu angka yang menyatakan keberhasilannya, yaitu kode keluar. Angka ini dapat dibaca melalui parameter khusus $? dan menjadi kontrak keberhasilan antarperintah, sebab keputusan rantai eksekusi bertumpu pada nilai itu. Topik ini membahas konvensi nilai kode keluar, cara membacanya, pemanfaatannya dalam operator && dan ||, serta penggunaannya dalam percabangan if dan skrip.
Kode keluar dan kontrak keberhasilan#
Konvensinya kontra-intuitif bagi pembelajar yang terbiasa dengan nilai boolean, yaitu kode keluar 0 berarti sukses, sedangkan nilai 1 sampai 255 berarti gagal. Alasan konvensi ini bersifat praktis, karena ada satu cara untuk berhasil tetapi banyak cara untuk gagal, dan kode yang berbeda dapat menyatakan penyebab kegagalan yang berbeda. Dua perintah bawaan shell mewakili kedua sisi tersebut, yaitu true yang selalu sukses dan false yang selalu gagal.
true
echo "kode keluar true: $?"
false
echo "kode keluar false: $?"kode keluar true: 0
kode keluar false: 1Setelah blok tersebut, $? kembali bernilai 0 karena perintah echo terakhir berhasil. Setiap perintah menimpa nilai ini, sehingga pembacaannya harus dilakukan segera setelah perintah yang dituju. Kebiasaan membaca $? segera akan terlatih dengan sendirinya ketika rantai eksekusi mulai dirangkai pada bagian berikutnya.
Rentang nilai dan pelipatan 8 bit#
Kode keluar hanya berukuran delapan bit, sehingga nilainya berada pada rentang 0 sampai 255. Nilai di luar rentang itu dilipat dengan sisa pembagian 256, sehingga exit 256 berakhir dengan kode keluar 0. Perilaku ini mudah menimbulkan kesalahan pada skrip yang menghitung kodenya secara bebas.
bash -c 'exit 3'
echo "kode keluar: $?"kode keluar: 3bash -c 'exit 256'
echo "kode keluar efektif: $?"kode keluar efektif: 0Perintah bash -c meluncurkan shell anak yang mengeksekusi teks perintahnya, sehingga exit 3 berakhir dengan kode keluar 3 yang terbaca oleh induknya. Pada blok kedua, 256 dilipat menjadi 0, dan kegagalan pun berubah menjadi sukses. Selain nilai bebas, terdapat konvensi yang dipakai sistem, yaitu 126 untuk perintah yang ditemukan tetapi tidak dapat dijalankan, 127 untuk perintah yang tidak ditemukan, serta 128 ditambah nomor sinyal untuk proses yang dituntaskan sinyal.
Membaca kode keluar dengan $?#
Parameter $? selalu memuat kode keluar dari perintah terakhir yang selesai dijalankan. Nilainya tertimpa segera setelah perintah berikutnya selesai, termasuk oleh echo yang bertugas menampilkannya. Apabila nilainya baru dibaca beberapa langkah kemudian, simpan ke dalam variabel terlebih dahulu. Perintah yang gagal biasanya ikut mencetak pesan error ke aliran error, yaitu saluran keluaran yang terpisah dari keluaran biasa, sehingga kode keluar dan pesannya saling melengkapi.
ls /tidak-ada-folder
echo "kode keluar: $?"ls: cannot access '/tidak-ada-folder': No such file or directory
kode keluar: 2Perintah ls mencetak pesan errornya ke aliran error, lalu berakhir dengan kode keluar 2. Angka 2 pada ls menyatakan berkas yang diminta tidak dapat diakses, sedangkan angka 1 lazim dipakai perintah lain sebagai gagalan umum. Makna angka selain 0 dan 1 sepenuhnya ditentukan oleh masing-masing perintah, sehingga halaman manual perintah terkait menjadi rujukan yang tepat ketika kodenya perlu ditafsirkan.
Rantai eksekusi dengan && dan ||#
Operator && melanjutkan eksekusi ke perintah berikutnya hanya bila perintah sebelumnya sukses, sedangkan || melanjutkan hanya bila sebelumnya gagal. Keduanya membaca kode keluar secara otomatis, sehingga pola ini menjadi pemakaian kode keluar yang paling sering terlihat. Rantai && yang panjang akan berhenti pada perintah gagal yang pertama, dan perintah setelahnya tidak dijalankan sama sekali.
printf 'hijau\nkuning\n' > warna.txt
grep hijau warna.txt && echo "pola ditemukan"hijau
pola ditemukangrep merah warna.txt
echo "kode keluar grep: $?"
grep merah warna.txt || echo "pola tidak ditemukan"kode keluar grep: 1
pola tidak ditemukanPerintah grep sukses ketika pola ditemukan dan gagal dengan kode keluar 1 ketika tidak ada baris yang cocok. Pada blok pertama, baris hijau tercetak oleh grep, kemudian && menjalankan echo karena kodenya 0. Pada blok kedua, grep tidak mencetak apa pun karena pola merah tidak ada, lalu || mengambil alih dan mencetak pesan penggantinya. Pola || seperti ini lazim dipakai sebagai penangan kegagalan yang ringkas.
Kode keluar dalam percabangan if#
Pernyataan if mengeksekusi perintah kondisinya, lalu memilih cabang berdasarkan kode keluarnya, dengan 0 dianggap benar dan nilai lain dianggap salah. Skrip yang dirancang baik menetapkan kontrak kode keluarnya secara jelas, yaitu kode apa yang berarti sukses dan kode apa yang berarti tiap jenis kegagalan. Berkas cek-berkas.sh berikut adalah skrip pemeriksa keberadaan berkas yang menerapkan kontrak tersebut, dengan kode keluar 0 untuk berkas yang ada dan 1 untuk yang tidak ada.
#!/usr/bin/env bash
# Memeriksa keberadaan berkas pada argumen pertama.
# Kode keluar skrip menjadi kontrak keberhasilan yang dibaca pemanggil.
if [ "$#" -eq 0 ]; then
:
elif [ -f "$1" ]; then
echo "berkas ada"
exit 0
else
echo "berkas tidak ditemukan" >&2
exit 1
fiPemanggilan tanpa argumen tidak dianggap kasus yang bermakna bagi skrip ini, sehingga skrip berhenti tanpa pesan pada cabang pertama. Dua blok berikut memanggil skrip dengan argumen berkas yang ada dan yang tidak ada, lalu menampilkan kode keluarnya.
bash cek-berkas.sh cek-berkas.sh
echo "kode keluar: $?"berkas ada
kode keluar: 0bash cek-berkas.sh arsip-hilang.txt
echo "kode keluar: $?"berkas tidak ditemukan
kode keluar: 1Pada pemanggilan pertama, skrip memeriksa dirinya sendiri, menemukan berkasnya, dan berakhir dengan 0. Pada pemanggilan kedua, pesan error dicetak ke aliran error dan skrip berakhir dengan 1. Pemanggil dengan if atau && kini dapat mengandalkan kedua kode tersebut tanpa menafsirkan teks keluarannya, dan itulah guna kontrak kode keluar.
Kesalahan umum#
Kekeliruan pada kode keluar biasanya baru terasa ketika rantai eksekusi berperilaku tidak masuk akal. Daftar berikut memuat yang paling sering ditemui beserta perbaikannya.
- Mengira kode keluar 1 berarti benar, mengikuti kebiasaan boolean. Konvensi shell justru memakai 0 untuk sukses, sehingga arah syarat pada
ifperlu diperiksa ulang. - Membaca
$?setelah perintah lain dieksekusi. Nilainya sudah tertimpa, misalnya oleh echo yang mencetaknya. Baca segera atau simpan ke variabel. - Memakai
exitdengan nilai di atas 255 pada skrip. Nilai tersebut dilipat dengan sisa pembagian 256, sehinggaexit 256justru melaporkan sukses. Pertahankan kode keluar pada rentang 0 sampai 255. - Menilai keberhasilan dari teks keluaran alih-alih kode keluarnya. Teks dapat berubah antarversi perangkat lunak, sedangkan kode keluar adalah kontrak yang stabil.
Ringkasan#
- Kode keluar 0 menyatakan sukses, sedangkan nilai 1 sampai 255 menyatakan gagal dengan arti yang ditentukan masing-masing perintah.
$?memuat kode keluar perintah terakhir dan tertimpa segera oleh perintah berikutnya.- Operator
&&dan||memakai kode keluar untuk merangkai eksekusi bersyarat tanpa pernyataan if. - Skrip menetapkan kontraknya melalui
exit, danifmemilih cabang berdasarkan kode 0 atau bukan 0.
Referensi#
- GNU Bash Reference Manual — Free Software Foundation — Menjelaskan exit status, parameter $?, serta operator && dan || pada daftar perintah.
- GNU Coreutils Manual — Free Software Foundation — Mendokumentasikan perilaku ls beserta kode keluarnya ketika berkas tidak dapat diakses.