Не останавливайте создание, если команда не выполнена, но проверьте состояние выхода

22

Я пытаюсь дать команду GNU Make 3.81 не останавливаться в случае сбоя команды (поэтому я ставлю команду с префиксом -), но я также хочу проверить состояние завершения следующей команды и распечатать более информативное сообщение. Однако мой Makefile ниже не работает:

$ cat Makefile 
all:
    -/bin/false
    ([ $$? -eq 0 ] && echo "success!") || echo "failure!"
$
$ make
/bin/false
make: [all] Error 1 (ignored)
([ $? -eq 0 ] && echo "success!") || echo "failure!"
success!

Почему Makefile выше эхом "успех!" вместо "провал!" ?

Обновить:

Следуя и расширяя принятый ответ, ниже следует, как он должен быть написан:

failure:                                                                                                                                                                                                                                      
    @-/bin/false && ([ $$? -eq 0 ] && echo "success!") || echo "failure!"                                                                                                                                                                 
success:                                                                                                                                                                                                                                      
    @-/bin/true && ([ $$? -eq 0 ] && echo "success!") || echo "failure!"     
Маркус Юний Брут
источник
2
Возможно, вы захотите изучить .ONESHELL:директиву.
Джонатан Леффлер
.ONESHELL будет запускать все блоки получения в одной оболочке, что имеет эффект: если первая команда завершится неудачно, последующие будут выполнены без проблем. Для предотвращения этого .SHELLFLAGS = -ecследует использовать. Но в этом случае вы не можете использовать -префикс больше (для личной команды квитанции), потому что make напишет, что ошибка игнорируется, но все равно завершится с ошибкой весь блок. Таким образом, || :это решение игнорировать команду. Но это не кроссплатформенность (у Windows нет || :или нет || true)
Paul-AG

Ответы:

14

Каждая команда обновления в правиле Makefile выполняется в отдельной оболочке. Так $? не содержит состояние завершения предыдущей неудачной команды, оно содержит значение по умолчанию для $? в новой оболочке. Вот почему ваш [$? -eq 0] тест всегда завершается успешно.

Кайл Джонс
источник
10

Вам не нужен тест, $?поскольку он &&работает, если он $?равен нулю, и ||выполняется в случае ненулевого возвращаемого значения.

И вам не нужен минус, поскольку возвращаемое значение make берется из последнего вызова программы продолжения строки. Так что это работает нормально

отказ:

      @/bin/false && echo "success!" || echo "failure!" 

успех:

      @/bin/true && echo "success!" || echo "failure!"

Происходит обратное: если вы хотите сделать свое собственное сообщение и все равно прервать процесс make с ненулевым значением, вам нужно написать что-то вроде этого:

отказ:

      @/bin/false && echo "success!" || { echo "failure!"; exit 1; }
Andreas
источник
8

Из GNU сделайте документацию :

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

Чтобы использовать makeстатус выхода в таком случае, выполните makeиз скрипта:

#!/bin/bash
make
([ $? -eq 0 ] && echo "success!") || echo "failure!"

И ваш Makefile содержит:

all:
    /bin/false
Тимоти Мартин
источник