Neden 0 doğru, ancak kabukta 1 yanlıştır?


122
false; echo $?

Yukarıdakiler, 1bildiğim diğer tüm programlama dilleriyle çelişen çıktı verecektir .

Bunun herhangi bir nedeni var mı?


3
Aynı zamanda Unix Way ile uyumludur ... başarıya geri dönmeyin.
Abdullah Cibaly

21
Çünkü çıkış durumu bir boole değildir. Bu kadar basit.
Jens

2
falseDiğer programlama dillerinde olduğu gibi bunun bir mantıksal olmadığını unutmayın . Bu sadece /bin/false( /usr/bin/falseMac'te) adresinde bulunan ve her zaman bir hata çıkış kodu 1 döndürmesi amaçlanan bir programdır true. Yani burada döküm diye bir şey yok. Her şey çıkış kodlarıyla ilgili.
Mikhail Vasin

Kabuk, bir işletim sistemine (kullanıcı) arayüzüdür. Unix vb. Programlar , cevaplarda verilen sebeple (birden fazla başarısızlık nedeni ile iletişim kurma yeteneği) OK olarak çıkma kuralını izler . Kabuk, yapıları if myprog; then echo OK; fikolay ve sezgisel hale getiren bu kuralı basitçe korur . Aksi takdirde, bir programın başarısı için her testi tersine çevirmeniz gerekir!
Peter - Monica'yı yeniden

Yanıtlar:


93

Bu bir kongredir, ancak onu düşündüğünüzde özellikle yararlıdır. Genel olarak, bir program başarılı olursa bilmeniz gereken tek şey budur. Ancak başarısız olursa, başarısızlıkla ilgili her türlü bilgiyi bilmeniz gerekebilir - neden olduğu, nasıl düzeltileceği vb. Sıfır anlamına gelen 'başarı' ve sıfır olmayan ortalama başarısızlık, başarıyı oldukça kolay bir şekilde kontrol etmenizi sağlar. ve isterseniz daha fazla ayrıntı için belirli hatayı araştırın. Birçok API ve çerçevenin benzer bir kuralı vardır - başarılı olan işlevler 0 döndürür ve başarısız olanlar belirli bir hata durumunu açıklayan bir hata kodu verir.


6
Bu yanıtı anlıyorum, ancak bool'dan int'e dönüşümün neden tersine çevrildiğini hala anlamıyorum. Şöyle bir "dönüş mantıksal kuralı" var mı: eğer doğru döndürürseniz, bu hata olmadığı anlamına gelir, yanlış döndürürseniz, bir hata oluştuğu anlamına gelir (daha iyi bilinen "tamsayı = hata kodu kuralı" gibi)?
Guillaume86

1
Bir mantıksal-int dönüşümü olduğunu varsaymak, cevabı gerçekten anlamadığınız anlamına gelir. Sıfır başarı anlamına gelir ve 1, 2, ..., 255'in tümü, farklı hata senaryolarını faydalı bir şekilde iletebilen hata kodlarıdır. Belirli bir örnek, xargsbir komut grubunun nasıl başarısız olduğunu göstermek için 127 civarındaki farklı hata kodlarını kullanandır . Yapılabilecek dönüşüm, 0'ın başarıya eşlendiği (ki bunun doğru / 1 olarak ifade etmek istediğinizi tahmin ediyorum; ancak bunun sadece başka bir keyfi kural olduğunu anlayın) ve diğer tüm değerleri başarısızlığa götüren int to bool'dur.
üçlü

79

Bash bir programlama (komut dosyası oluşturma) dilidir, ancak aynı zamanda bir kabuk ve bir kullanıcı arayüzüdür. Hata 0ise, program yalnızca bir tür hata gösterebilir.

Ancak Bash'de sıfır olmayan herhangi bir değer bir hatadır ve bir hatayı temsil etmek için 1-255 arasında herhangi bir sayı kullanabiliriz. Bu, birçok farklı türde hataya sahip olabileceğimiz anlamına gelir. 1genel bir hatadır, 126bir dosyanın yürütülemeyeceği 127anlamına gelir, 'komut bulunamadı' anlamına gelir, vb. Burada , en yaygın çıkış kodlarından bazılarını gösteren Özel Anlamlara Sahip Bash Çıkış Kodlarının bir listesi bulunmaktadır .

Ayrıca birçok başarı türü vardır (çıkış durumu 0). Ancak, başarı bir sonraki adıma geçmenize olanak tanır - sonuçları bir ekrana yazdırmayı veya bir komutu çalıştırmayı vb. Beğenebilirsiniz.


8
Çeşitli geri dönüş kodlarının yararlılığını gösteren bu pragmatik cevap, diğer cevapların bazılarının vaazlarına tercih edilir.
javadba

1
Ve sadece eğlenmek için, temsil ettikleri kongre 1980'lere kadar uzansa da, belki de daha istek /usr/include/sysexits.huyandıran çıkış değerlerine dikkat çekeceğim . Bu kural bash kapsamı dışında bulunmaktadır.
ghoti

2
Harika, basit ve pragmatik bir açıklama. Bu en üstte olmalı.
Rey Leonard Amorato

3
"Hata 0ise, program yalnızca bir tür hata sunabilir" . Bu ifade anahtardır ve bu cevabın neden en üstte olması gerektiğinin nedeni.
rayryeng

1
@LuisLavaire Bu tanımlanmamış bir davranış. Pratikte, sayı kesilme eğilimindedir; ancak çalışma zamanı bir uyarı oluşturduysa ve / veya basitçe çökerse kesinlikle "daha yanlış" olmazdı. İşletim sistemi bu bilgi için tam olarak bir bayt ayırdı ve birden fazla bayt koymaya çalışırken kesinlikle bir hata var. Ancak işletim sistemi tasarımcıları muhtemelen ilk gün çökmelerle karşılaştılar ve omuzlarını silktiler ve yapabileceklerinin en iyisinin değeri kesip yoluna devam etmek olduğuna karar verdiler.
üçlü

30

Burada birbiriyle ilişkili iki konu var.

İlk olarak, OP'nin sorusu, neden 0 doğru ama yanlış 1'dir? ve ikincisi, uygulamalar neden başarı için 0 ve başarısızlık için sıfır olmayan döndürür?

OP'nin sorusunu cevaplamak için ikinci soruyu anlamamız gerekir. Bu gönderiye verilen sayısız cevap, bunun bir sözleşme olduğunu açıkladı ve bu sözleşmenin sağladığı bazı güzellikleri listeledi. Bu niteliklerden bazıları aşağıda özetlenmiştir.

Uygulamalar neden başarı için 0, başarısızlık için sıfır olmayan döndürür?

Bir işlemi çağıran kodun, işlemin çıkış durumu hakkında iki şeyi bilmesi gerekir. İşlem başarıyla çıktı mı? [* 1] Ve eğer işlem başarılı bir şekilde çıkmazsa, neden işlem başarısız bir şekilde çıktı? Başarıyı belirtmek için herhangi bir değer kullanılabilir. Ancak 0, platformlar arasında taşınabilir olduğu için diğer numaralardan daha kullanışlıdır. Xibo'nun 16 Ağustos 2011'de bu soruya verdiği cevabı özetlersek :

Sıfır, kodlamadan bağımsızdır.

32 bitlik tamsayı bir kelimede bir (1) saklamak istersek, ilk soru "büyük endian kelimesi veya küçük-endian kelimesi?" Ve ardından "küçük endian kelimesini oluşturan baytlar ne kadar uzun?" Olacaktır. ", sıfır ise hep aynı görünecektir.

Ayrıca, bazı insanların bir noktada errno'yu char veya short atmaları, hatta float yapmaları beklenmelidir. (int) ((char) ENOLCK), char en az 8 bit uzunluğunda olmadığında ENOLCK değildir (7 bit ASCII karakterli makineler UNIX tarafından desteklenir), (int) ((char) 0) ise 0'dan bağımsızdır. charın mimari detayları.

Başarı için 0'ın dönüş değeri olacağı belirlendikten sonra, başarısızlık için sıfır olmayan herhangi bir değer kullanmak mantıklıdır. Bu, birçok çıkış kodunun işlemin neden başarısız olduğu sorusuna yanıt vermesini sağlar .

Neden 0 doğru, ancak kabukta 1 yanlıştır?

Kabukların temel kullanımlarından biri, süreçleri komut dosyası oluşturarak otomatikleştirmektir. Genellikle bu, bir işlemi çağırmak ve ardından işlemin çıkış durumuna bağlı olarak koşullu olarak başka bir şey yapmak anlamına gelir. Philippe A. , bu gönderiye verdiği cevabın

Bash ve unix kabuklarda genel olarak, dönüş değerleri boole değildir. Tamsayı çıkış kodlarıdır.

Bu işlemlerin çıkış durumunu bir boole değeri olarak yorumlamak gerekir. Başarılı ( 0) bir çıkış durumunu doğru ve sıfır olmayan / başarısız çıkış durumlarını yanlış olarak eşlemek mantıklıdır . Bunu yapmak, zincirleme kabuk komutlarının koşullu yürütülmesine izin verir.

İşte bir örnek mkdir deleteme && cd $_ && pwd. Kabuk 0'ı doğru olarak yorumladığından, bu komut beklendiği gibi rahatlıkla çalışır. Kabuk, 0'ı yanlış olarak yorumlayacaksa, her işlem için yorumlanan çıkış durumunu tersine çevirmeniz gerekir.

Kısacası, uygulamaların başarılı bir çıkış durumu için 0 döndürdüğü düşünüldüğünde, kabuğun 0'ı yanlış olarak yorumlaması mantıksız olacaktır.


[* 1]: Evet, çoğu zaman işlemlerin basit bir başarı mesajından fazlasını döndürmesi gerekir, ancak bu, bu iş parçacığının kapsamı dışındadır.

Ayrıca Gelişmiş Bash Komut Dosyası Oluşturma Kılavuzundaki Ek E'ye bakın.


2
Merhaba, Şunu vurgulamak gerekirse, eğer kabuk sıfırı yanlış ve sıfır olmayanı doğru olarak yorumluyorsa, yapmanın hilesi mkdir deleteme && cd _$ && pwdgerçekten başarısız olmazdı; ama bunu mkdir deleteme || cd _$ || pwd, benim görüşüme göre çok daha az açık olan ile değiştirmemiz gerekir , çünkü aslında yapmak istediğimiz şey mkdir deleteme" ve " cd _$" ve " pwd... ("ve" burada sıradan dilden gelen anlamı ile).
Rémi Peyre

1
Sanırım cevabımda bunu ele aldım. Yine de açık olmak gerekirse, mantığı tersine çevirdiğinizde sadece &&operatörleri operatörlerle değiştirmek yeterli değildir ||. De Morgan yasasını tam olarak uygulamanız gerekir. Bakınız: en.wikipedia.org/wiki/De_Morgan%27s_laws
axiopisty

1
Başka bir değerlendirme: Genel olarak truesıfıra falsekarşılık gelen ve sıfırdan farklı bir ifadeye karşılık gelmenin doğal olmasının en az üç nedenini görüyorum . Birincisi, size bir şey söylersem, “size doğruyu söylemiş olmak” söylediğim yalanların sayısına bağlıdır: ya sıfırdır ve ben (küresel olarak) doğruyu söyledim ya da sıfırdan farklıdır ve yalan söyledim. Bu, temelde mantıksal olanın toplamanın andortak “ve” sine karşılık gelmesini istemekle aynıdır ( tabii ki doğal sayılarla sınırlandırıldığında).
Rémi Peyre

1
(önceki yorumdan devam). İkinci neden, tek bir gerçek olduğu, ancak birçok gerçek olmayanların olmasıdır; bu nedenle, için tek bir değeri trueve için diğer tüm değerleri ilişkilendirmek daha uygundur false. (Bu, esasen programların dönüş değerleri ile ilgili hususlarla aynıdır).
Rémi Peyre

(önceki yorumdan devam). Üçüncü neden, "A'nın doğru olduğu doğru" ile "A'nın doğru olduğu", "yanlış olduğu kadar yanlış" olduğu, "yanlış olan A" ile aynı olmasıdır, vb .; böylece bu trueçarpımsal 1 ve falseçarpımsal -1 olarak davranır . Bu, -1'in trueüsleri olarak ek olarak "çift" ve false"tuhaf" olarak davranması anlamına gelir . Yine truesıfır olmayı hak eden şey ...
Rémi Peyre

17

Anlamayı önemli bulduğum tek temel nokta şudur. Bash ve unix kabuklarda genel olarak, dönüş değerleri boole değildir. Tamsayı çıkış kodlarıdır. Bu nedenle, 0'ın başarı anlamına geldiğini ve diğer değerlerin bir miktar hata olduğunu söyleyerek bunları kongreye göre değerlendirmelisiniz.

İle test, [ ]ya da [[ ]]operatörlerin, deneme şartları 0 çıkış kodu (arasında / bin / doğru sonuç) durumunda doğru olarak değerlendirir. Aksi takdirde yanlış olarak değerlendirirler.

Dizeler, çıkış kodlarından farklı şekilde değerlendirilir:

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

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

(( ))Aritmetik operatör true ve false olarak 1 ve 0 yorumlar. Ancak bu operatör test, [ ]veya için tam bir yedek olarak kullanılamaz [[ ]]. Aritmetik operatörün ne zaman yararlı olduğunu gösteren bir örnek:

for (( counter = 0 ; counter < 10 ; counter ++ )) ; do
  if (( counter % 2 )) ; then echo "odd number $counter" ; fi
done

Doğru / yanlış üzerindeki parantez ve parantez açıklaması için teşekkürler
javadba

15

Bu sadece bir 0 çıkış kodunun başarı anlamına geldiği bir kuraldır. EXIT_SUCCESS hemen hemen her modern sistemde 0 olacaktır.

DÜZENLE:

"neden hem test 0 hem de test 1 0 (başarılı) döndürüyor?"

Bu tamamen farklı bir soru. Yanıt, tek bir bağımsız değişkeni test etmek için iletmek, bu bağımsız değişken boş dizge ("") olmadığı sürece her zaman başarılı olur. Açık Grup belgelerine bakın .


O zaman neden her ikisi test 0ve test 1iadeler 0 (başarılı)?
httpinterpret

5
@httpinterpret, testsayısal değerleri test etmez. Bu dizenin boş dizge olup olmadığını sınar. man testdaha fazla bilgi için.
Carl Norum

12

Tipik olarak programlar başarı için sıfır, başarısızlık için sıfır olmayan döndürür; falseUygun bir sıfır olmayan değer olduğu için 1 döndürür, ancak genellikle sıfır olmayan herhangi bir değer, bir tür başarısızlık anlamına gelir ve birçok program, farklı hata modlarını belirtmek için farklı sıfır olmayan değerler döndürür


2
Hiçbir açıklaması olmayan (veya bariz bir nedeni) olmayan olumsuz oylar berbattır ve bunu yapanlar topluma hiç yardımcı olmadıkları için topaldırlar.
Abdullah Cibaly

1
Değil o Affetmeksizin ... ama olan onların 2 puan ... ve @MichaelMrozek .. 19.6k ile lol, çok kötü zarar veremez.
Alex Grey

1
@alexgray Bu iki yıl önceydi; o sırada yaklaşık 5k'm vardı. Ve cevabın neyin yanlış olduğunu, temsilciden çok merak ettim
Michael Mrozek


4

Unix'in ilk günlerine kadar uzanan bir sözleşmedir.

Geleneksel olarak, tüm sistem çağrıları başarılı olursa 0 döndürür, aksi takdirde sıfır değildir, çünkü bu durumda farklı başarısızlık nedenlerini belirtmek için farklı numaralar kullanılabilir.

Kabuklar bu kuralı izler, 0 en son komutun başarılı olduğu anlamına gelir, aksi takdirde sıfır değildir. Benzer şekilde, sıfır olmayan dönüş değeri, çıkış hata mesajları için kullanışlıdır: örneğin 1: "beyin öldü", 2: "kalpsiz" vb.



3

Doğru / yanlışı başarı / başarısızlıkla eşitlemeye çalışmanız.

Bunlar tamamen iki, ama ilk başta incelikli olsa da, farklı ikilikler!

Kabuk betiklemede doğru / yanlış diye bir şey yoktur. Kabuk 'ifadeleri' doğru / yanlış olarak yorumlanmaz. Daha ziyade, kabuk 'ifadeleri' başarılı veya başarısız olan işlemlerdir.

Açıktır ki, bir süreç birçok nedenden dolayı başarısız olabilir. Bu nedenle, olası hataları eşleştirmek için daha büyük bir set koduna ihtiyacımız var. Pozitif tamsayılar işe yarar. Öte yandan, süreç başarılı olursa, bu tam olarak yapması gerekeni yaptığı anlamına gelir. Bunu yapmanın tek bir yolu olduğundan, sadece bir koda ihtiyacımız var. 0 hile yapar.

C'de bir program oluşturuyoruz. Bir kabuk betiğinde, bir şeyler yapmak için bir dizi program çalıştırıyoruz.

Fark!


Kafa karıştırıcı. "Adam [" yazın. Test yardımcı programının ifadeyi değerlendirdiğini ve doğru olarak değerlendirirse sıfır (doğru) çıkış durumunu döndürdüğünü gösterir; aksi takdirde 1 (yanlış) döndürür. İfade yoksa, test ayrıca 1 (yanlış) döndürür.
süvari

1

Belki hatırlamanın iyi bir yolu şudur:

  • Dönüş kodları yanıtı "yanıt nedir?" doğru (veya başka bir sonuç) veya yanlış
  • Çıkış kodları yanıtı "sorun nedir?" çıkış kodu veya sorun yok (0)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.