No deje de hacerlo si falla un comando, pero verifique el estado de salida

22

Estoy tratando de indicarle a GNU Make 3.81 que no se detenga si falla un comando (así que prefiero el comando con -), pero también quiero verificar el estado de salida en el siguiente comando e imprimir un mensaje más informativo. Sin embargo, mi Makefile a continuación falla:

$ 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!

¿Por qué el Makefile anterior hace eco de "éxito"! en lugar de "fracaso" ?

actualizar:

A continuación y ampliando la respuesta aceptada, a continuación se explica cómo debe escribirse:

failure:                                                                                                                                                                                                                                      
    @-/bin/false && ([ $$? -eq 0 ] && echo "success!") || echo "failure!"                                                                                                                                                                 
success:                                                                                                                                                                                                                                      
    @-/bin/true && ([ $$? -eq 0 ] && echo "success!") || echo "failure!"     
Marcus Junius Brutus
fuente
2
Es posible que desee investigar la .ONESHELL:directiva.
Jonathan Leffler
.ONESHELL ejecutará todos los bloques de recibos en un shell que tiene efecto: si el primer comando falla, los siguientes se ejecutarán sin problemas. Para evitar esto se .SHELLFLAGS = -ecdebe utilizar. Pero en este caso no puede usar el -prefijo más (para el comando personal del recibo) porque la marca escribirá que el error se ignora pero aún fallará todo el bloque. Entonces, || :es una la solución para ignorar el comando. Pero no es multiplataforma (Windows no tiene || :o || true)
Paul-AG

Respuestas:

14

Cada comando de actualización en una regla de Makefile se ejecuta en un shell separado. Entonces $? no contiene el estado de salida del comando fallido anterior, contiene el valor predeterminado para $? en una nueva concha. Es por eso que tu [$? -eq 0] la prueba siempre tiene éxito.

Kyle Jones
fuente
10

No necesita la prueba de $?ya que &&funciona si $?es cero y ||se procede en caso de un valor de retorno distinto de cero.

Y no necesita el signo menos, ya que el valor de retorno para realizar se toma de la última llamada al programa de la línea. Entonces esto funciona bien

fracaso:

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

éxito:

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

Sucede lo contrario: si quieres hacer tu propio mensaje y quieres interrumpir el proceso de creación de todos modos con un valor distinto de cero, debes escribir algo como esto:

fracaso:

      @/bin/false && echo "success!" || { echo "failure!"; exit 1; }
Andreas
fuente
8

Desde la documentación de GNU make :

Cuando se deben ignorar los errores, ya sea por un indicador '-' o '-i', haga que los intentos devuelvan un error igual que el éxito , excepto que imprime un mensaje que le indica el código de estado con el que salió el shell, y dice que el error ha sido ignorado.

Para utilizar makeel estado de salida de un caso como este, ejecute makedesde un script:

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

Y haga que su Makefile contenga:

all:
    /bin/false
Timothy Martin
fuente