Почему 0 истинно, а ложь 1 в оболочке?

122
false; echo $?

Вышеупомянутое будет выводить 1, что противоречит всем другим языкам программирования, которые я знаю.

В чем причина?

httpinterpret
источник
3
Это также соответствует Unix Way ... ничего не возвращайте в случае успеха.
Абдулла Джибали
21
Потому что статус выхода не является логическим. Просто как тот.
Jens
2
Имейте в виду, что falseэто не логическое значение, как в других языках программирования. Это просто программа, расположенная в /bin/false( /usr/bin/falseна Mac), которая всегда должна возвращать код выхода из ошибки 1. Аналогично для true. Так что здесь нет такого понятия, как кастинг. Все дело в кодах выхода.
Михаил Васин
Оболочка - это (пользовательский) интерфейс операционной системы. Программы Unix и т. Д. Следуют соглашению о выходе с 0 как OK по причине, указанной в ответах (возможность сообщить более одной причины сбоя). Оболочка просто придерживается этого соглашения, что делает конструкции if myprog; then echo OK; fiпростыми и интуитивно понятными. В противном случае вам придется инвертировать каждый тест для успеха программы!
Питер - Восстановить Монику

Ответы:

93

Это соглашение, но оно особенно полезно, если задуматься. В общем, если программа работает успешно, это все, что вам нужно знать. Однако, если это не удается, вам может потребоваться вся информация о сбое - почему он произошел, как его исправить и т. Д. Наличие нулевого среднего значения «успех» и ненулевого среднего значения сбоя позволяет вам довольно легко проверить успех. , и при желании изучите конкретную ошибку для получения дополнительных сведений. Многие API и фреймворки имеют схожее соглашение: успешно завершившиеся функции возвращают 0, а те, которые терпят неудачу, возвращают код ошибки, описывающий конкретный случай сбоя.

Карл Норум
источник
6
Я понимаю этот ответ, но до сих пор не понимаю, почему преобразование bool в int инвертировано. Существует ли «логическое соглашение о возврате», которое гласит: если вы вернете истину, это означает, что ошибок нет, если вы вернете ложь, это означает, что произошла ошибка (например, «целое число = соглашение о коде ошибки», которое более известно)?
Guillaume86
1
Предположение, что существует преобразование логического значения в int, означает, что вы действительно не поняли ответ. Ноль означает успех, а все 1, 2, ..., 255 - это коды ошибок, которые могут эффективно сообщать о различных сценариях сбоя. Конкретным примером является xargsиспользование различных кодов ошибок в диапазоне около 127, чтобы указать, как группа команд не удалась. Преобразование, которое может быть выполнено, - это int в bool, где 0 соответствует успеху (что, я думаю, вы хотите выразить как true / 1; но поймите, что это просто еще одно произвольное соглашение), а все другие значения - до отказа.
tripleee
79

Bash - это язык программирования (сценариев), но это также оболочка и пользовательский интерфейс. Если это 0была ошибка, то программа могла выдать только один вид ошибки.

Однако в Bash любое ненулевое значение является ошибкой, и мы можем использовать любое число от 1-255 для представления ошибки. Это означает, что у нас может быть много разных ошибок. 1является общей ошибкой, 126означает, что файл не может быть выполнен, 127означает «команда не найдена» и т. д. Вот список кодов выхода Bash со специальными значениями, показывающий некоторые из наиболее распространенных кодов выхода.

Есть также много видов успеха (статус выхода 0). Однако успех позволит вам перейти к следующему шагу - вы можете напечатать результаты на экране, выполнить команду и т. Д.

Стефан Ласевски
источник
8
Этот прагматичный ответ, демонстрирующий полезность различных кодов возврата, предпочтительнее проповеднической проповеди некоторых других ответов.
javadba 06
1
И просто для удовольствия, я отмечу, что /usr/include/sysexits.hзначения выхода заметок , возможно, более амбициозны, хотя условность, которую они представляют, восходит к 1980-м годам. Это соглашение существует за пределами bash.
ghoti
2
Отличное, простое и прагматичное объяснение. Это должно быть наверху.
Рей Леонард Аморато
3
«Если 0была ошибка, то программа могла выдать только один вид ошибки» . Это утверждение является ключевым, и причина, по которой этот ответ должен быть вверху.
rayryeng
1
@LuisLavaire Это неопределенное поведение. На практике число имеет тенденцию к усечению; но определенно не было бы «более неправильным», если бы среда выполнения генерировала предупреждение и / или просто аварийно завершала работу. ОС зарезервировала ровно один байт для этой информации, и попытка поместить более одного байта определенно вызывает ошибку. Но разработчики ОС, вероятно, столкнулись с ошибками в первый же день, пожали плечами и решили, что лучшее, что они могут сделать, - это просто сократить значение и двигаться дальше.
Tripleee
30

Здесь есть две связанные проблемы.

Во-первых, вопрос OP: почему 0 истинно, а ложь 1 в оболочке? и второй: почему приложения возвращают 0 в случае успеха и ненулевое значение в случае неудачи?

Чтобы ответить на вопрос ОП, нам нужно понять второй вопрос. В многочисленных ответах на этот пост говорится, что это соглашение, и перечислены некоторые из нюансов, которые оно предоставляет. Некоторые из этих тонкостей кратко описаны ниже.

Почему приложения возвращают 0 в случае успеха и ненулевое значение в случае неудачи?

Код, который вызывает операцию, должен знать две вещи о статусе завершения операции. Операция завершилась успешно? [* 1] А если операция не завершилась успешно, почему операция завершилась неудачно? Для обозначения успеха можно использовать любое значение. Но 0 удобнее любого другого числа, потому что он переносится между платформами. Обобщая ответ xibo на этот вопрос 16 августа 2011 года:

Ноль не зависит от кодировки.

Если бы мы хотели сохранить единицу (1) в 32-битном целочисленном слове, первым вопросом было бы «слово с прямым порядком байтов или слово с прямым порядком байтов?», За которым следовало бы «какова длина байтов, составляющих слово с прямым порядком байтов?». ", а ноль всегда будет выглядеть одинаково.

Также следует ожидать, что в какой-то момент некоторые люди приведут errno к char, short или даже к float. (int) ((char) ENOLCK) не является ENOLCK, если длина char не превышает 8 бит (машины с 7-битными символами ASCII поддерживаются UNIX), а (int) ((char) 0) равно 0 независимо от архитектурные детали чар.

Как только будет определено, что 0 будет возвращаемым значением для успеха, тогда имеет смысл использовать любое ненулевое значение для неудачи. Это позволяет множеству кодов выхода ответить на вопрос, почему операция не удалась.

Почему 0 истинно, а ложь 1 в оболочке?

Одно из основных применений оболочек - автоматизация процессов путем их написания сценариев. Обычно это означает вызов операции, а затем выполнение чего-то еще, условно в зависимости от статуса завершения операции. Филипп А. хорошо объяснил в своем ответе на этот пост, что

В bash и в оболочках unix в целом возвращаемые значения не являются логическими. Это целые коды выхода.

Затем необходимо интерпретировать статус завершения этих операций как логическое значение. Имеет смысл сопоставить 0статус выхода успешный ( ) с истиной, а любой ненулевой / неудачный статус выхода - с ложью. Это позволяет условно выполнять связанные команды оболочки.

Вот пример mkdir deleteme && cd $_ && pwd. Поскольку оболочка интерпретирует 0 как истину, эта команда работает должным образом. Если бы оболочка интерпретировала 0 как ложь, вам пришлось бы инвертировать интерпретируемый статус выхода для каждой операции.

Короче говоря, для оболочки было бы бессмысленно интерпретировать 0 как ложь, учитывая соглашение, согласно которому приложения возвращают 0 при успешном статусе выхода.


[* 1]: Да, во многих случаях операции должны возвращать нечто большее, чем просто сообщение об успешном выполнении, но это выходит за рамки этой темы.

См. Также Приложение E в Advanced Bash-Scripting Guide

axiopisty
источник
2
Здравствуйте! Просто хочу подчеркнуть, что, если бы оболочка интерпретировала ноль как ложь, а ненулевое значение как истину, трюк на mkdir deleteme && cd _$ && pwdсамом деле не потерпел бы неудачу; но мы должны были бы заменить его на mkdir deleteme || cd _$ || pwd, что, на мой взгляд, гораздо менее ясно, потому что на самом деле мы хотим сделать mkdir deleteme« и », cd _$« и » pwd... (с «и», имеющим здесь свое значение из обычного языка).
Реми Пейр
1
Думаю, я сказал об этом в своем ответе. Однако для ясности: когда вы инвертируете логику, недостаточно просто заменить &&операторы ||операторами. Вам нужно будет полностью применить закон Де Моргана. См .: en.wikipedia.org/wiki/De_Morgan%27s_laws
axiopisty
1
Еще одно соображение: я вижу по крайней мере три причины, по которым в целом было бы естественным утверждение, которое trueсоответствует нулю и falseсоответствует ненулевому. Во-первых, если я говорю вам что-то, «сказав вам правду» зависит от количества лжи, которую я сказал: либо оно равно нулю, и я сказал (глобально) правду, либо это ненулевое значение, и я солгал. По сути, это то же самое, что и желание, чтобы логическое andсоответствовало общему «и» сложения (очевидно, при ограничении натуральными числами).
Реми Пейр
1
(продолжение предыдущего комментария). Вторая причина в том, что истина одна, а неправды много; так что удобнее связать одно значение для trueи все остальные значения для false. (По сути, это то же самое, что и рассмотрение возвращаемых значений программ).
Реми Пейр,
(продолжение предыдущего комментария). Третья причина состоит в том, что «верно, что верно, что A» - это то же самое, что «верно, что A», «ложно, что неверно, что A» - это то же самое, что «неверно, что A» и т. Д .; так что trueведет себя как мультипликативный 1 и falseкак мультипликативный -1. Что, как степень -1, означает, что он trueведет себя как «четное» и falseкак «нечетное». Опять же, это то, trueчто заслуживает того, чтобы быть нулевым ...
Реми Пейр
17

Я считаю важным понять один фундаментальный момент. В bash и в оболочках unix в целом возвращаемые значения не являются логическими. Это целые коды выхода. Таким образом, вы должны оценивать их в соответствии с соглашением, согласно которому 0 означает успех, а другие значения означают некоторую ошибку.

С test, [ ]или [[ ]]операторы, условия Баш оценить , как верно в случае выхода кода от 0 (результат / бен / истинным). В противном случае они оцениваются как ложные.

Строки оцениваются иначе, чем коды выхода:

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

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

(( ))Арифметический оператор интерпретирует 1 и 0 , как истинные и ложные. Но этот оператор нельзя использовать в качестве полной замены test, [ ]или [[ ]]. Вот пример, показывающий, когда полезен арифметический оператор:

for (( counter = 0 ; counter < 10 ; counter ++ )) ; do
  if (( counter % 2 )) ; then echo "odd number $counter" ; fi
done
Филипп А.
источник
Спасибо за объяснение фигурных скобок и круглых скобок для истинно / ложно
javadba
15

Это просто соглашение, что код выхода 0 означает успех. EXIT_SUCCESS будет 0 почти в каждой современной системе.

РЕДАКТИРОВАТЬ:

"почему и тест 0, и тест 1 возвращают 0 (успех)?"

Это совсем другой вопрос. Ответ заключается в том, что передача одного аргумента для проверки всегда приводит к успеху, если только этот аргумент не является пустой строкой (""). См. Документацию Open Group .

Мэтью Флашен
источник
Тогда почему оба test 0и test 1возвращает 0 (успех)?
httpinterpret
5
@httpinterpret, testне проверяет числовые значения. Он проверяет, является ли эта строка пустой строкой. man testЧтобы получить больше информации.
Карл Норум
12

Обычно программы возвращают ноль в случае успеха и ненулевое значение в случае неудачи; falseвозвращает 1, потому что это удобное ненулевое значение, но обычно любое ненулевое значение означает какой-либо сбой, и многие программы будут возвращать разные ненулевые значения, чтобы указать разные режимы сбоя

Майкл Мрозек
источник
2
Голоса против без объяснения (или очевидной причины) - отстой, а те, кто это делают, - отстойные, потому что они вообще не помогают сообществу.
Абдулла Джибали
1
Не попустительство это ... но это их 2 очка ... и @MichaelMrozek .. с 19.6k, он не может повредить слишком плохо, лол.
Alex Grey
1
@alexgray Это было два года назад; на тот момент у меня было около 5к. И мне было больше любопытно, что не так с ответом, чем с представителем
Майкл Мрозек
5

AFAIK это исходит из соглашения C, что вы должны вернуть 0 в случае успеха. Видеть:

man close

Большая часть API C (POSIX) построена таким образом. http://en.wikipedia.org/wiki/C_POSIX_library

mathk
источник
4

это соглашение, восходящее к ранним дням существования Unix.

По соглашению, все системные вызовы возвращают 0 в случае успеха и ненулевое значение в противном случае, потому что тогда для обозначения другой причины отказа могут использоваться разные числа.

Оболочки следуют этому соглашению, 0 означает, что последняя команда выполнена успешно, в противном случае - ненулевое значение. Точно так же ненулевое возвращаемое значение пригодится для вывода сообщений об ошибках: например, 1: «мозг мертв», 2: «бессердечный» и так далее.


источник
Это ответ.
Питер - Восстановить Монику
3

Вы пытаетесь приравнять истину / ложь к успеху / неудаче.

Это две совершенно, хотя поначалу тонко, разные дихотомии!

В сценариях оболочки нет такого понятия, как истина / ложь. «Выражения» оболочки не интерпретируются как истина / ложь. Скорее «выражения» оболочки - это процессы, которые либо завершаются успешно, либо терпят неудачу.

Очевидно, что процесс может потерпеть неудачу по многим причинам. Таким образом, нам нужен больший набор кодов для сопоставления возможных сбоев. Положительные целые числа делают свое дело. С другой стороны, если процесс завершился успешно, это означает, что он сделал именно то, что должен был сделать. Поскольку есть только один способ сделать это, нам нужен только один код. 0 делает свое дело.

На языке C мы создаем программу. В сценарии оболочки мы запускаем кучу программ, чтобы что-то сделать.

Разница!

captaincurrie
источник
Это сбивает с толку. Введите "мужчина [". Он показывает, что тестовая утилита оценивает выражение и, если оно истинно, возвращает нулевой (истинный) статус выхода; в противном случае возвращается 1 (ложь). Если выражения нет, test также возвращает 1 (ложь).
кавалькада
1

Может быть, хороший способ запомнить это:

  • Коды возврата отвечают "какой ответ?" истина (или другой результат) или ложь
  • Коды выхода отвечают "в чем проблема?" код выхода или нет проблем (0)
jjisnow
источник