Mengapa 0 benar tetapi salah adalah 1 di shell?

122
false; echo $?

Di atas akan muncul 1, yang bertentangan dengan semua bahasa pemrograman lain yang saya tahu.

Ada alasan dalam hal ini?

httpinterpret
sumber
3
Ini juga sejalan dengan Unix Way ... jangan mengembalikan apa pun pada kesuksesan.
Abdullah Jibaly
21
Karena status keluar bukanlah boolean. Sederhana seperti itu.
Jens
2
Perlu diingat bahwa falseini bukan boolean, seperti pada bahasa pemrograman lainnya. Ini hanya program yang terletak di /bin/false( /usr/bin/falsedi Mac) yang dimaksudkan untuk selalu mengembalikan kode keluar kesalahan 1. Mirip untuk true. Jadi tidak ada yang namanya casting di sini. Ini semua tentang kode keluar.
Mikhail Vasin
Shell adalah antarmuka (pengguna) ke sistem operasi. Program Unix dll mengikuti konvensi keluar dengan 0 sebagai OK, untuk alasan yang diberikan dalam jawaban (kemampuan untuk berkomunikasi lebih dari satu alasan kegagalan). Shell hanya mempertahankan konvensi ini, yang membuat konstruksi menjadi if myprog; then echo OK; fimudah dan intuitif. Jika tidak, Anda harus membalik setiap tes untuk keberhasilan program!
Peter - Pulihkan Monica

Jawaban:

93

Ini konvensi, tetapi sangat berguna ketika Anda memikirkannya. Secara umum, jika suatu program berhasil hanya itu yang perlu Anda ketahui. Namun, jika gagal, Anda mungkin perlu mengetahui semua jenis informasi tentang kegagalan - mengapa itu terjadi, bagaimana memperbaikinya, dll. Memiliki nol berarti 'sukses' dan bukan nol berarti kegagalan memungkinkan Anda dapat memeriksa kesuksesan dengan cukup mudah , dan selidiki kesalahan tertentu untuk detail lebih lanjut jika Anda mau. Banyak API dan kerangka kerja memiliki konvensi serupa - fungsi yang berhasil mengembalikan 0 dan yang gagal mengembalikan kode kesalahan yang menjelaskan kasus kegagalan tertentu.

Carl Norum
sumber
6
Saya memahami jawaban ini, tetapi saya masih tidak mengerti mengapa konversi bool ke int terbalik. Apakah ada "konvensi boolean pengembalian" yang mengatakan: jika Anda mengembalikan nilai benar, berarti tidak ada kesalahan, jika Anda mengembalikan salah, itu berarti terjadi kesalahan (seperti "konvensi kode kesalahan = integer" yang lebih terkenal)?
Guillaume86
1
Dengan asumsi ada konversi boolean ke int menyiratkan bahwa Anda tidak benar-benar memahami jawabannya. Nol berarti sukses dan semua 1, 2, ..., 255 adalah kode kesalahan yang berguna untuk mengkomunikasikan berbagai skenario kegagalan. Contoh khusus adalah xargsyang menggunakan kode kesalahan berbeda dalam kisaran sekitar 127 untuk menunjukkan bagaimana sekelompok perintah gagal. Konversi yang dapat dilakukan adalah int ke bool di mana 0 memetakan menuju sukses (yang saya kira Anda ingin nyatakan sebagai true / 1; tetapi sadari bahwa ini hanyalah konvensi sewenang-wenang lainnya) dan semua nilai lain menuju kegagalan.
tripleee
79

Bash adalah bahasa pemrograman (skrip), tetapi juga merupakan shell dan antarmuka pengguna. Jika 0ada kesalahan, maka program hanya bisa menampilkan satu jenis kesalahan.

Namun di Bash, nilai bukan nol adalah kesalahan, dan kami dapat menggunakan angka apa pun dari 1-255 untuk merepresentasikan kesalahan. Ini berarti kami dapat memiliki berbagai jenis kesalahan. 1adalah kesalahan umum, 126artinya file tidak dapat dieksekusi, 127berarti 'perintah tidak ditemukan', dll. Berikut daftar Kode Keluar Bash Dengan Arti Khusus yang menunjukkan beberapa kode keluar yang paling umum.

Ada juga banyak macam kesuksesan (status keluarnya 0). Namun, keberhasilan akan memungkinkan Anda untuk melanjutkan ke langkah berikutnya — Anda dapat menyukai hasil cetak ke layar, atau menjalankan perintah, dll.

Stefan Lasiewski
sumber
8
Jawaban pragmatis yang menunjukkan kegunaan berbagai kode pengembalian lebih disukai daripada khotbah dari beberapa jawaban lainnya.
javadba
1
Dan hanya untuk bersenang-senang, saya akan menunjukkan bahwa /usr/include/sysexits.hcatatan nilai keluar yang mungkin lebih aspiratif, meskipun konvensi yang mereka wakili sudah ada sejak tahun 1980-an. Konvensi ini ada di luar cakupan bash.
ghoti
2
Penjelasan yang bagus, sederhana dan pragmatis. Ini harus di atas.
Rey Leonard Amorato
3
"Jika 0ada kesalahan, maka program hanya dapat menampilkan satu jenis kesalahan" . Pernyataan ini adalah kunci dan alasan mengapa jawaban ini harus menjadi yang teratas.
rayryeng
1
@LuisLavaire Itu adalah perilaku yang tidak ditentukan. Dalam praktiknya, jumlahnya cenderung terpotong; tetapi tidak akan menjadi "lebih salah" jika runtime menghasilkan peringatan dan / atau crash. OS mencadangkan tepat satu byte untuk informasi ini dan mencoba memasukkan lebih dari satu byte pasti ada kesalahan. Tetapi perancang OS mungkin mengalami crash pada hari pertama, dan mengangkat bahu, dan memutuskan bahwa yang terbaik yang dapat mereka lakukan adalah memotong nilainya dan melanjutkan.
tripleee
30

Ada dua masalah terkait di sini.

Pertama, pertanyaan OP, Mengapa 0 benar tetapi salah adalah 1 di shell? dan yang kedua, mengapa aplikasi mengembalikan 0 untuk sukses dan bukan nol untuk kegagalan?

Untuk menjawab pertanyaan OP kita perlu memahami pertanyaan kedua. Berbagai jawaban untuk posting ini telah menjelaskan bahwa ini adalah konvensi dan telah mencantumkan beberapa kebaikan yang diberikan konvensi ini. Beberapa dari kebaikan ini dirangkum di bawah ini.

Mengapa aplikasi mengembalikan 0 untuk sukses dan bukan nol untuk kegagalan?

Kode yang memanggil operasi perlu mengetahui dua hal tentang status keluar dari operasi. Apakah operasi berhasil keluar? [* 1] Dan jika operasi tidak berhasil keluar, mengapa operasi tersebut tidak berhasil keluar? Nilai apa pun dapat digunakan untuk menunjukkan kesuksesan. Tetapi 0 lebih nyaman daripada angka lain karena portabel antar platform. Meringkas jawaban Xibo untuk ini pertanyaan pada 16 Agustus 2011:

Zero tidak bergantung pada pengkodean.

Jika kita ingin menyimpan satu (1) dalam kata integer 32-bit, pertanyaan pertama adalah "kata big-endian atau kata little-endian?", Diikuti dengan "berapa lama byte menyusun kata little-endian? ", sedangkan nol akan selalu terlihat sama.

Juga perlu diharapkan bahwa beberapa orang melemparkan errno ke char atau short di beberapa titik, atau bahkan melayang. (int) ((char) ENOLCK) bukan ENOLCK jika char tidak setidaknya sepanjang 8-bit (mesin char ASCII 7-bit didukung oleh UNIX), sedangkan (int) ((char) 0) adalah 0 independen dari detail arsitektur char.

Setelah ditentukan bahwa 0 akan menjadi nilai kembali untuk sukses, maka masuk akal untuk menggunakan nilai bukan nol untuk kegagalan. Ini memungkinkan banyak kode keluar untuk menjawab pertanyaan mengapa operasi gagal.

Mengapa 0 benar tetapi salah adalah 1 di shell?

Salah satu kegunaan dasar shell adalah mengotomatiskan proses dengan membuat skrip. Biasanya ini berarti meminta operasi dan kemudian melakukan sesuatu yang lain secara bersyarat berdasarkan status keluar dari operasi tersebut. Philippe A. menjelaskan dengan baik dalam jawaban postingannya ini bahwa

Dalam bash dan shell unix secara umum, nilai yang dikembalikan bukanlah boolean. Mereka adalah kode keluar integer.

Maka perlu untuk menafsirkan status keluar dari operasi ini sebagai nilai boolean. Masuk akal untuk memetakan 0status keluar yang berhasil ( ) ke benar dan status keluar yang bukan nol / gagal ke salah. Melakukan ini memungkinkan eksekusi bersyarat dari perintah shell yang dirantai.

Berikut ini contohnya mkdir deleteme && cd $_ && pwd. Karena shell mengartikan 0 sebagai benar, perintah ini bekerja dengan nyaman seperti yang diharapkan. Jika shell menafsirkan 0 sebagai salah maka Anda harus membalikkan status keluar yang ditafsirkan untuk setiap operasi.

Singkatnya, tidak masuk akal bagi shell untuk menafsirkan 0 sebagai salah mengingat konvensi bahwa aplikasi mengembalikan 0 untuk status keluar yang berhasil.


[* 1]: Ya, berkali-kali operasi perlu menghasilkan lebih dari sekadar pesan sukses sederhana tetapi itu berada di luar cakupan utas ini.

Lihat juga Lampiran E dalam Panduan Pembuatan Skrip Bash Lanjutan

aksiopisti
sumber
2
Halo, Hanya untuk menekankan bahwa, jika shell menafsirkan nol sebagai salah dan bukan nol sebagai benar, trik melakukan mkdir deleteme && cd _$ && pwdtidak akan benar-benar gagal; tapi kita harus menggantinya dengan mkdir deleteme || cd _$ || pwd, yang menurut saya kurang jelas, karena yang sebenarnya ingin kita lakukan adalah mkdir deletemedancd _$danpwd... (dengan “dan” di sini artinya dari bahasa biasa).
Rémi Peyre
1
Saya pikir saya membahasnya dalam jawaban saya. Agar lebih jelas, ketika Anda membalik logika, tidak cukup hanya mengganti &&operator dengan ||operator. Anda harus menerapkan sepenuhnya hukum De Morgan. Lihat: en.wikipedia.org/wiki/De_Morgan%27s_laws
axiopisty
1
Pertimbangan lain: Saya melihat setidaknya tiga alasan mengapa, secara umum, wajar untuk menyatakan bahwa truesesuai dengan nol dan falsesesuai dengan bukan nol. Pertama, jika saya memberi tahu Anda sesuatu, "setelah mengatakan yang sebenarnya" tergantung pada jumlah kebohongan yang telah saya katakan: apakah itu nol dan saya telah mengatakan (secara global) kebenaran, atau itu bukan nol dan saya telah berbohong. Ini pada dasarnya sama dengan menginginkan logika andsesuai dengan "dan" umum dari penjumlahan (ketika membatasi ke bilangan asli, jelas).
Rémi Peyre
1
(lanjutan dari komentar sebelumnya). Alasan kedua adalah bahwa ada satu kebenaran tetapi banyak yang tidak benar; jadi, akan lebih mudah untuk mengaitkan satu nilai untuk truedan semua nilai lainnya untuk false. (Ini pada dasarnya sama dengan pertimbangan tentang nilai kembali program).
Rémi Peyre
(lanjutan dari komentar sebelumnya). Alasan ketiga adalah bahwa “benar bahwa benar bahwa A” sama dengan “benar bahwa A”, “salah itu salah bahwa A” sama dengan “salah itu A”, dll .; sehingga trueberperilaku sebagai perkalian 1 dan falsesebagai perkalian -1. Yang, sebagai pangkat -1, berarti trueberperilaku tambahan sebagai "genap" dan falsesebagai "ganjil". Sekali lagi, ini trueyang layak menjadi nol ...
Rémi Peyre
17

Satu hal mendasar yang saya anggap penting untuk dipahami adalah ini. Dalam bash dan shell unix secara umum, nilai yang dikembalikan bukanlah boolean. Mereka adalah kode keluar integer. Dengan demikian, Anda harus mengevaluasinya sesuai dengan konvensi yang mengatakan 0 berarti sukses, dan nilai lain berarti beberapa kesalahan.

Dengan test, [ ]atau [[ ]]operator, kondisi bash dievaluasi sebagai true jika kode keluar 0 (hasil dari / bin / true). Jika tidak, mereka menilai sebagai salah.

String dievaluasi secara berbeda dari kode keluar:

if [ 0 ] ; then echo not null ; fi
if [ $(echo 0) ] ; then echo not null ; fi

if [ -z "" ] ; then echo null ; fi

The (( ))Operator aritmatika menafsirkan 1 dan 0 sebagai benar dan salah. Tetapi operator itu tidak dapat digunakan sebagai pengganti lengkap test, [ ]atau [[ ]]. Berikut adalah contoh yang menunjukkan kapan operator aritmatika berguna:

for (( counter = 0 ; counter < 10 ; counter ++ )) ; do
  if (( counter % 2 )) ; then echo "odd number $counter" ; fi
done
Philippe A.
sumber
Terima kasih atas penjelasan braces vs tanda kurung pada benar / salah
javadba
15

Ini hanya konvensi bahwa kode keluar 0 berarti sukses. EXIT_SUCCESS akan menjadi 0 di hampir setiap sistem modern.

EDIT:

"mengapa tes 0 dan tes 1 menghasilkan 0 (berhasil)?"

Itu pertanyaan yang sama sekali berbeda. Jawabannya adalah meneruskan satu argumen untuk menguji selalu menghasilkan kesuksesan kecuali argumen itu adalah string null (""). Lihat dokumentasi Open Group .

Matthew Flaschen
sumber
Lalu mengapa keduanya test 0dan test 1mengembalikan 0 (sukses)?
httpinterpretasikan
5
@httpinterpret, testtidak menguji nilai numerik. Ini menguji apakah string itu adalah string nol atau tidak. man testuntuk informasi lebih lanjut.
Carl Norum
12

Biasanya program mengembalikan nol untuk sukses, bukan nol untuk kegagalan; falsemengembalikan 1 karena ini adalah nilai bukan nol yang nyaman, tetapi umumnya nilai bukan nol berarti kegagalan, dan banyak program akan mengembalikan nilai bukan nol yang berbeda untuk menunjukkan mode kegagalan yang berbeda

Michael Mrozek
sumber
2
Suara negatif tanpa penjelasan (atau alasan yang jelas) menyebalkan apa pun dan mereka yang melakukannya lumpuh karena mereka sama sekali tidak membantu masyarakat.
Abdullah Jibaly
1
Tidak memaafkannya… tapi itu adalah 2 poin mereka… dan @MichaelMrozek .. dengan 19.6k, tidak ada salahnya terlalu buruk, lol.
Alex Grey
1
@alexgray Ini terjadi dua tahun lalu; pada saat itu saya memiliki sekitar 5k. Dan saya lebih penasaran apa yang salah dengan jawabannya daripada tentang perwakilannya
Michael Mrozek
4

itu adalah konvensi tanggal kembali ke hari-hari awal Unix.

Menurut konvensi, semua panggilan sistem mengembalikan 0 jika berhasil, bukan nol sebaliknya, karena angka yang berbeda dapat digunakan untuk menunjukkan alasan kegagalan yang berbeda.

Kerang mengikuti konvensi ini, 0 berarti perintah terakhir berhasil, bukan nol jika tidak. Demikian pula, nilai kembali bukan nol berguna untuk pesan kesalahan keluaran: misalnya 1: "mati otak", 2: "tidak berperasaan", dan seterusnya.


sumber
Inilah jawabannya.
Peter - Pulihkan Monica
3

Anda mencoba menyamakan benar / salah dengan sukses / gagal.

Mereka adalah dua sepenuhnya, meskipun pada awalnya halus, dikotomi yang berbeda!

Dalam skrip shell, tidak ada yang namanya benar / salah. 'Ekspresi' shell tidak diartikan sebagai benar / salah. Sebaliknya, 'ekspresi' shell adalah proses yang berhasil atau gagal.

Jelas, suatu proses mungkin gagal karena berbagai alasan. Jadi kita membutuhkan kode set yang lebih besar untuk memetakan kemungkinan kegagalan. Bilangan bulat positif berhasil. Di sisi lain, jika prosesnya berhasil, itu berarti ia melakukan apa yang seharusnya dilakukannya. Karena hanya ada satu cara untuk melakukan itu, kita hanya membutuhkan satu kode. 0 berhasil.

Di C, kami membuat program. Dalam skrip shell, kami menjalankan banyak program untuk menyelesaikan sesuatu.

Perbedaan!

captaincurrie
sumber
Ini membingungkan. Ketik 'man ['. Ini menunjukkan Utilitas uji mengevaluasi ekspresi dan, jika mengevaluasi ke benar, mengembalikan status keluar nol (benar); jika tidak, ia mengembalikan 1 (salah). Jika tidak ada ekspresi, pengujian juga mengembalikan 1 (salah).
iring
1

Mungkin cara yang baik untuk mengingatnya adalah:

  • Kode Return menjawab "apa jawabannya?" benar (atau hasil lain) atau salah
  • Kode keluar menjawab "apa masalahnya?" kode keluar atau tidak ada masalah (0)
jisnow
sumber