Захватить код выхода команды выхода

10

У меня есть это в сценарии Bash:

exit 3;

exit_code="$?"

if [[ "$exit_code" != "0" ]]; then
    echo -e "${r2g_magenta}Your r2g process is exiting with code $exit_code.${r2g_no_color}";
    exit "$exit_code";
fi

Похоже, он выйдет сразу после команды выхода, что имеет смысл. Мне было интересно, есть ли какая-то простая команда, которая может предоставить код выхода, не выходя сразу?

Я собирался угадать:

exec exit 3

но он выдает сообщение об ошибке: exec: exit: not found. Что я могу сделать? :)

G-Man говорит: «Восстанови Монику»
источник
1
Да, exec exit 3это не Буэно, я получаю"exec: exit: not found"
7
Я не понимаю вопроса. Почему бы не установить exit_code=3и полностью исключить exit 3линию?
wjandrea
@wjandrea - скорее концептуальный вопрос, чем практический
2
Это все еще не имеет смысла для меня. Зачем нужен код выхода, если вы на самом деле не выходите?
Бармар
1
@ Barmar каждый процесс имеет код выхода. Большинство людей, пытающихся ответить на вопрос, интерпретируют вопрос как «чем я могу заменить« выход 3 »в сценарии, чтобы он устанавливал $?переменную, но не выходил из этого сценария»?
Икар

Ответы:

32

Если у вас есть скрипт, который запускает какую-то программу и смотрит на состояние завершения программы (с  $?), и вы хотите протестировать этот скрипт, выполнив что-то, что заставляет $?быть установлено какое-то известное значение (например,  3), просто выполните

(exit 3)

Скобки создают вложенную оболочку. Затем exitкоманда заставляет эту вложенную оболочку завершиться с указанным состоянием выхода.

G-Man говорит: «Восстанови Монику»
источник
Кроме того, для целей отладки было бы так же просто установить exit_code="3"для тестирования
Centimane
1
Да, wjandrea указал на это вчера.
G-Man говорит «Восстановить Монику»
12

exitэто встроенный Bash, так что вы не можете execэто сделать. В соответствии с руководством Bash :

Состояние выхода Bash - это состояние выхода последней команды, выполненной в скрипте. Если команды не выполняются, статус выхода равен 0.

Собирая все это вместе, я бы сказал, что ваш единственный вариант - сохранить желаемый статус выхода в переменной, а затем exit $MY_EXIT_STATUSпри необходимости.

solarshado
источник
хммм, что ты думаешь об идее @ G-man?
2
Может быть, я неправильно понял, что вы пытаетесь достичь. Если вы просто пытаетесь установить $?(хотя я не совсем уверен, почему вы это сделаете), это кажется надежным ответом. Если вы просто хотите установить какое-либо неудачное значение, falseэто еще один вариант.
Соларшадо
10

Вы можете написать функцию, которая возвращает статус, указанный в качестве аргумента, или, 255если ничего не указано. (Я называю это, retпоскольку это "возвращает" свое значение.)

ret() { return "${1:-255}"; }

и использовать retвместо вашего звонкаexit . Это позволяет избежать неэффективности создания вложенной оболочки в принятом в настоящее время ответе.

Некоторые измерения.

time bash -c 'for i in {1..10000} ; do (exit 3) ; done ; echo $?'

на моей машине занимает около 3,5 секунд.

 time bash -c 'ret(){ return $1 ; } ; for i in {1..10000} ; do ret 3 ; done ; echo $?'

на моей машине занимает около 0,051 секунды, в 70 раз быстрее. Ввод обработки по умолчанию все еще оставляет в 60 раз быстрее. Очевидно, что цикл имеет некоторые накладные расходы. Если я изменю тело цикла на «просто» :или trueтогда время уменьшится вдвое до 0,025, совершенно пустой цикл будет недопустимым синтаксисом. Добавление ;:в цикл показывает, что эта минимальная команда занимает 0,007 секунды, поэтому накладные расходы цикла составляют около 0,018. Вычитание этих накладных расходов из двух тестов показывает, что retрешение более чем в 100 раз быстрее.

Очевидно, что это синтетическое измерение, но все складывается. Если вы делаете все в 100 раз медленнее, чем нужно, то в итоге вы получаете медленные системы. 0.0

Икар
источник
2
@iBug Дополнительное пространство не требуется.
Икар
Хорошая мысль о неэффективности создания суб-оболочки. Я читал, что некоторые оболочки могут быть достаточно умными, чтобы оптимизировать раскладку в подобных случаях, но этот bash не входит в их число.
G-Man говорит: «Восстановите Монику»
3

О exec exit 3... он попытается запустить внешнюю команду с именем exit, но ее нет, поэтому вы получите ошибку. Это должна быть внешняя команда, а не встроенная в оболочку, поскольку она полностью exec заменяет оболочку. Это также означает, что даже если у вас была вызвана внешняя команда exit, exec exit 3вы не вернетесь, чтобы продолжить сценарий оболочки, поскольку оболочки больше не будет .

ilkkachu
источник
1
Я думаю, вы могли бы сделать exec bash -c "exit 3", но в настоящее время я не могу придумать ни одной причины, чтобы сделать это, в отличие от просто exit 3.
Дэвид З
1
@DavidZ, в любом случае, exec«или просто exit» остановит сценарий, что не похоже на то, чего хотел вопрос.
ilkkachu
3

Вы можете сделать это с Awk:

awk 'BEGIN{exit 9}'

Или сед:

sed Q9 /proc/stat
Стивен Пенни
источник
... или с раковиной:sh -c 'exit 9'
ilkkachu
1
@ilkkachu, если ты собираешься сделать это, ты мог бы также сделать (exit 9)в принятом ответе
Стивен Пенни