LINUX.ORG.RU

Код завершения программ. Несколько вопросов!

 ,


0

1

В Linux есть возможность проверить (в консоли), с каким кодом завершилась программа.

echo $?

Обычно 0 (true) означает корректное завершение, а 1 (false) - с ошибками. Но прочитал, что это не обязательно всегда так. Типа это общепринятые обозначения в программировании, и их надо придерживаться, но коды могут быть разными. А зачем нужно что-то кроме 0 и 1? Какие еще состояния программы бывают, кроме «корректно завершилась» или «вышла с ошибками»? Можно ли тут в пример привести разные Windows-программы, которые иногда падают и вылезают ошибки вида «0x1234» что-то такое, или это не то? Не совсем понятно, о чем такие ошибки могут сказать пользователю.

Собственно, прочел, что и в баш-скрипте можно самому задать код завершения в нужном месте, например, так.

return_number=1
exit $return_number

И потом проверить его с помощью echo $? (по крайне мере, первый вызов этой штуки после завершения скрипта точно сработает... потом будет почему-то всегда 0 показывать).

Но заметил такую штуку, что если записать определенную команду в if, и заставить выполнить какое-то действие по завершению команды...

if `программа`
then
    делаем какие-то действия, если программа вернула 0
else
    или что-то другое, если завершилась с 1
fi

То не всегда прокатывает, в отличии от голой консоли! Тут проблема в том, что походу (поправьте, если неправ) не все консольные программы в Linux возвращают true (0) или false (1) в качестве «последнего» вывода... не знаю как назвать короче. В общем есть команды, которые ничего не выводят на экран. У таких прокатывает фишка с получением кода возврата в конструкции if. А другие просто выкидывают вывод результатов выполнения в stdout, тогда через if непонятно как получить код возврата. Ведь оно возвращает ненужный результат выполнения вместо кода возврата.

И еще, как перевести на русский определение из мануала? Гугл какую-то нелепицу выдает.

($?) Expands to the exit status of the most recently executed foreground pipeline.

как перевести на русский определение из мануала?

Посмотри, что такое pipeline в том же мане и всё станет ясно

DllMain
()

А зачем нужно что-то кроме 0 и 1?

На случай если программа хочет конкретизировать а что же пошло не так.

Может быть простым как в ls (раздел «Exit status»): http://man7.org/linux/man-pages/man1/ls.1.html

Или сложным как в curl (раздел «EXIT CODES»): https://curl.haxx.se/docs/manpage.html

И потом проверить его с помощью echo $? (по крайне мере, первый вызов этой штуки после завершения скрипта точно сработает... потом будет почему-то всегда 0 показывать).

Потому что будет возвращать код возврата команды echo: ведь теперь она будет последней командой, верно?

($?) Expands to the exit status of the most recently executed foreground pipeline

(Я надеюсь что ты знаешь что такое пайпы)
Если запустить
prg1 | prg2
то код возврата какой команды должно давать $?: prg1 или prg2?

Kroz ★★★★★
()
Последнее исправление: Kroz (всего исправлений: 1)

Тут проблема в том, что походу (поправьте, если неправ) не все консольные программы в Linux возвращают true (0) или false (1) в качестве «последнего» вывода... не знаю как назвать короче.

Вы не хотите читать документацию и выдумываете магию. Любая программа может выводить, а может не выводить информацию. Но любая программа всегда завершается с кодом, это тянется уже 50 лет, когда компьютеры с Unix были маленькие и 16-битные, так до сих пор код возврата от 0 до 255.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 2)
Ответ на: комментарий от DllMain

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

shkolnik_2022
() автор топика
Ответ на: комментарий от Kroz

то код возврата какой команды должно давать $?: prg1 или prg2?

Для студентов вопрос сойдёт, но вообще этот динозавр уже давно протух и всем надоело, потому как только, но нестандартно, не извращаются, чтобы получить и то и другое и наоборот :)

vodz ★★★★★
()
Ответ на: комментарий от Kroz

Спасибо за примеры. Проверил, ввел [b]ls -aaaa[/b], выдает код возврата 2. Значит, в больших сложных программах программист сам определяет возможные пути ошибок и выдачу сообщений/кодов. Правда для пользователя я думаю предпочтительнее «человеческое» сообщение, как в типичных linux-командах.

Например, часто в Windows падала какая-то игра, и сообщение вида «Error code 0x1234ff». Не знаю зачем такой код возврата, ведь из него непонятно в чем проблема. Написали бы «Ошибка драйвера, обновите драйвер», или что-то такое, а тут непонятен смысл таких сообщений.

(Я надеюсь что ты знаешь что такое пайпы)

Да, я про них читал, что можно несколько программ запустить через «|», и каждая последующая будет получать результат работы (вывод) предыдущей в качестве входного аргумента.

то код возврата какой команды должно давать $?: prg1 или prg2?

По логике 2й конечно, она выполнится последней.

shkolnik_2022
() автор топика
Ответ на: комментарий от vodz

Вы не хотите читать документацию и выдумываете магию. Любая программа может выводить, а может не выводить информацию. Но любая программа всегда завершается с кодом, это тянется уже 50 лет, когда компьютеры с Unix были маленькие и 16-битные, так до сих пор код возврата от 0 до 255.

Это понятно, что она завершается с кодом. Но в конструкции if program мы не всегда получим код возврата. Если программа выдает что-то на экран, то код возврата внутри скрипта мы не получим. Есть мысль, что надо как-то сначала избавиться от ее стандартного вывода, куда-то день эти результаты.

shkolnik_2022
() автор топика
Ответ на: комментарий от shkolnik_2022

Но в конструкции if `program` мы не всегда получим код возврата. Если программа выдает что-то на экран, то код возврата внутри скрипта мы не получим. Есть мысль, что надо как-то сначала избавиться от ее стандартного вывода, куда-то день эти результаты.

Нет, вы получите всегда код возврата. Вам намекали, что если ваша `program` есть список программ через трубы: `cmd1 | cmd2`, то код возврата будет не у той программы, что вызвала проблему, (хотя и это можно добиться отпцией pipefail, см документацию на bash), а последней.

Поразмыслите:

$ ls x
ls: cannot access x: No such file or directory
$ if `ls x 2> /dev/null`; then echo Ok; else echo $?; fi
2
$ if `ls x 2> /dev/null | echo`; then echo Ok; else echo $?; fi
Ok

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

Что-то здесь не сходится.

Ввожу для примера через обычную консоль.

pwd
/home/aaa

echo $?
0

А теперь через скрипт.

if `pwd`
then
    echo 0
else
    echo 1
fi

Запускаем скрипт.

./myscript.sh: строка 3: /home/aaa: Это каталог
1
shkolnik_2022
() автор топика
if `программа`

Это буквально означает «взять текст который напечатала на stdout «программа» и попытаться исполнить его как shell-код в контексте оператора if». Результат может быть произвольный, в зависимости от того что выводит на печать «программа», и скорее всего не тот что нужно. А для проверки кода возврата правильно использовать конструкцию

if программа

(без backticks `,`).

d_a ★★★★★
()
Ответ на: комментарий от d_a

Реально спасибо, теперь понял как оно делается. С кавычками в if может прокатить любая программа вроде touch, которая ничего не выводит на экран. А без кавычек такие как pwd (ну или вообще все). Правда теперь не очень понятен смысл кавычек как таковых.

Вроде еще накопал другой вариант записи.

if $(команда)

Но там та же история, с командами вроде pwd код внутри скрипта не выдает.

shkolnik_2022
() автор топика
Ответ на: комментарий от shkolnik_2022

Например, часто в Windows падала какая-то игра, и сообщение вида «Error code 0x1234ff». Не знаю зачем такой код возврата,

Это не код возврата, это отдельное сообщение, не имеющее отношение к коду возврата. А код возврата может проверять родительский процесс, если ему это нужно

Harald ★★★★★
()
Ответ на: комментарий от Harald

Это не код возврата, это отдельное сообщение, не имеющее отношение к коду возврата.

Т.е. это сообщение не предусмотрено авторами программы? Непонятно кто тогда генерирует его и для кого.

shkolnik_2022
() автор топика
Ответ на: комментарий от Harald

Тогда ясно почему они такие «полезные» для обычных юзеров.

shkolnik_2022
() автор топика
Ответ на: комментарий от Harald

А вот с segmentation fault сталкивался на Linux, когда запускал какие-то игры. Но там вроде из-за проблем совместимости, нехватало каких-то библиотек в новой версии Ubuntu, некоторые игры при попытке запуска такую ошибку выдавали.

shkolnik_2022
() автор топика
Ответ на: комментарий от shkolnik_2022

А теперь через скрипт.

И с чего вы решили, что «через скрипт» надо писать if `cmd`? if проверяет результат команды, команда у вас получается из синтаксического выражения в обратных кавычках, что означает получить строку из вывода команды. Потому if `pwd` означает if /home/aaa, а это не команда, а каталог. Заканчивайте изучать shell методом тыка и откройте, наконец, документацию.

vodz ★★★★★
()

А зачем нужно что-то кроме 0 и 1?

perl -E 'for($i=0;$i<256;$i++){$!=$i;print("$i: $!\n");}'

mord0d ★★★★★
()
Ответ на: комментарий от shkolnik_2022

Правда для пользователя я думаю предпочтительнее «человеческое» сообщение, как в типичных linux-командах.

Для пользователя будет и человеческое сообщение. А для обработки ошибки в скриптах как раз человеческое сообщение не очень подходит; программам удобней работать с кодами.

то код возврата какой команды должно давать $?: prg1 или prg2?

По логике 2й конечно, она выполнится последней.

Угадал.

Но иногда нужен код первой. Например, когда prg1 выполняет что-то полезное, а prg2 просто записывает вывод в какой-то файл с помощью tee.

prg1 или prg2 - это поведение в bash можно поменять.

`команда`
$(команда)

Старайся не использовать первый вариант, а использовать второй.

Kroz ★★★★★
()
Ответ на: комментарий от shkolnik_2022

Блин, спасибо, не знал про то что кавычки можно было не ставить!

Не «можно было не ставить», а «нужно было не ставить».

Оператор if имеет следующий вид:


if команда
then
    # если команда вернула 0
else
    # если команда вернула не 0
fi

В вашем случае:

if `pwd`
   ^^^^^---- команда

А эта команда означает буквально следующее: выполнить то, что выведет pwd. Т.е. у вас это превратилось в:

if /home/aaa
   ^^^^^^^^^---- команда

А команда /home/aaa выполниться не может, поскольку это не исполнимый файл, а каталог. О чём сообщение об ошибке и сказало.

Rootlexx ★★★★★
()
Ответ на: комментарий от Kroz
`команда`
$(команда)

Старайся не использовать первый вариант, а использовать второй.

Хорошо, но есть ли разница? По эффекту вроде одинаковы. Правда по синтаксису 2й вариант мне нравится больше.

shkolnik_2022
() автор топика
Ответ на: комментарий от Rootlexx

Понял разницу, спасибо! Нашел подтверждение ваших слов в руководстве баша по if, а вот про использование кавычек `` в if там ни слова, может оно и не нужно, нигде не применяется особо.

shkolnik_2022
() автор топика
Ответ на: комментарий от shkolnik_2022

Хорошо, но есть ли разница? По эффекту вроде одинаковы. Правда по синтаксису 2й вариант мне нравится больше.

Эффект одинаковый. Но
1) Обратные кавычки хуже воспринимаются на глаз, то есть хуже читабельность кода
2) Не сделаешь вложенные конструкции, например: for F in $( $(echo "ls -1") ) ; do echo "== $F"; done (внимание: этот пример не работает для файлов с пробелами в имени)

может оно и не нужно, нигде не применяется особо.

Если оно тебе не нужно, не применяй. Даже мой пример вверху искусственный, так как почти такого же результата можно добиться с помощью for F in * ; do echo "== $F"; done (а этот пример корректно обрабатывает файлы с пробелами в имени)

Kroz ★★★★★
()
Последнее исправление: Kroz (всего исправлений: 1)
Ответ на: комментарий от shkolnik_2022

а вот про использование кавычек `` в if там ни слова

Обратные кавычки `` не имеют отношения конкретно к оператору if. Это так называемая подстановка команд, которая работает много где ещё, позволяя подставлять вывод одной команды в другую.

Пример:

aleksej@lenovo:~$ echo Время UTC: `date -u`
Время UTC: Вс фев 9 16:27:30 UTC 2020
aleksej@lenovo:~$ 

Здесь в команду echo подставляется вывод команды date -u.

В man bash всё написано.

Rootlexx ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.