Comment puis-je annuler la valeur de retour d’un processus?

Je cherche un processus de négation simple, mais multi-plateforme, qui annule la valeur renvoyée par un processus. Il doit mapper 0 à une valeur! = 0 et toute valeur! = 0 à 0, c’est-à-dire que la commande suivante devrait renvoyer “oui, le chemin non existant n’existe pas”:

ls nonexistingpath | negate && echo "yes, nonexistingpath doesn't exist." 

Le ! – l’opérateur est génial mais malheureusement pas indépendant du shell.

Auparavant, la réponse était présentée avec ce qui est maintenant la première section dans la dernière section.

POSIX Shell comprend un ! opérateur

En fouillant autour des spécifications du shell pour d’autres problèmes, j’ai récemment (septembre 2015) remarqué que le shell POSIX supportait un ! opérateur. Par exemple, il est répertorié en tant que mot réservé et peut apparaître au début d’un pipeline – où une commande simple est un cas particulier de «pipeline». Il peut donc être utilisé dans les instructions if et while ou while dans les shells compatibles POSIX. Par conséquent, malgré mes réserves, il est probablement plus disponible que ce que j’avais réalisé en 2008. Une vérification rapide de POSIX 2004 et SUS / POSIX 1997 le montre ! était présent dans ces deux versions.

Notez que le ! L’opérateur doit apparaître au début du pipeline et annule le code d’état de tout le pipeline (c’est-à-dire la dernière commande). Voici quelques exemples.

 # Simple commands, pipes, and redirects work fine. $ ! some-command succeed; echo $? 1 $ ! some-command fail | some-other-command fail; echo $? 0 $ ! some-command < succeed.txt; echo $? 1 # Environment variables also work, but must come after the !. $ ! RESULT=fail some-command; echo $? 0 # A more complex example. $ if ! some-command < input.txt | grep Success > /dev/null; then echo 'Failure!'; recover-command; mv input.txt input-failed.txt; fi Failure! $ ls *.txt input-failed.txt 

Réponse portable – fonctionne avec des coquilles antiques

Dans un script Bourne (Korn, POSIX, Bash), j’utilise:

 if ...command and arguments... then : it succeeded else : it failed fi 

C’est aussi portable que possible. La commande et les arguments peuvent être un pipeline ou une autre séquence composée de commandes.

Une commande not

Le ‘!’ l’opérateur, qu’il soit intégré à votre shell ou fourni par le système d’exploitation, n’est pas disponible partout. Cependant, le code ci-dessous date d’au moins 1991 (même si je pense que j’ai déjà écrit une version précédente). Je n’ai pas tendance à l’utiliser dans mes scripts, car il n’est pas disponible de manière fiable.

 /* @(#)File: $RCSfile: not.c,v $ @(#)Version: $Revision: 4.2 $ @(#)Last changed: $Date: 2005/06/22 19:44:07 $ @(#)Purpose: Invert success/failure status of command @(#)Author: J Leffler @(#)Copyright: (C) JLSS 1991,1997,2005 */ #include  #include  #include  #include  #include "stderr.h" #ifndef lint static const char sccs[] = "@(#)$Id: not.c,v 4.2 2005/06/22 19:44:07 jleffler Exp $"; #endif int main(int argc, char **argv) { int pid; int corpse; int status; err_setarg0(argv[0]); if (argc < = 1) { /* Nothing to execute. Nothing executed successfully. */ /* Inverted exit condition is non-zero */ exit(1); } if ((pid = fork()) < 0) err_syserr("failed to fork\n"); if (pid == 0) { /* Child: execute command using PATH etc. */ execvp(argv[1], &argv[1]); err_syserr("failed to execute command %s\n", argv[1]); /* NOTREACHED */ } /* Parent */ while ((corpse = wait(&status)) > 0) { if (corpse == pid) { /* Status contains exit status of child. */ /* If exit status of child is zero, it succeeded, and we should exit with a non-zero status */ /* If exit status of child is non-zero, if failed and we should exit with zero status */ exit(status == 0); /* NOTREACHED */ } } /* Failed to receive notification of child's death -- assume it failed */ return (0); } 

Cela retourne ‘succès’, l’opposé de l’échec, lorsqu’il ne parvient pas à exécuter la commande. Nous pouvons débattre de la pertinence de l’option «ne rien faire avec succès». Peut-être devrait-il signaler une erreur quand on lui demande de ne rien faire. Le code dans "stderr.h" fournit des fonctions simples de rapport d’erreur – je l’utilise partout. Code source sur demande – voir ma page de profil pour me contacter.

Dans Bash, utilisez le! opérateur avant la commande. Par exemple:

 ! ls nonexistingpath && echo "yes, nonexistingpath doesn't exist" 

Tu pourrais essayer:

 ls nonexistingpath || echo "yes, nonexistingpath doesn't exist." 

ou juste:

 ! ls nonexistingpath 

Si vous n’arrivez pas à utiliser Bash comme shell (par exemple, les scripts git ou les tests d’exécution de marionnettes), vous pouvez exécuter:

echo '! ls notexisting' | bash

-> retcode: 0

echo '! ls /' | bash

-> retcode: 1

 ! ls nonexistingpath && echo "yes, nonexistingpath doesn't exist." 

ou

 ls nonexistingpath || echo "yes, nonexistingpath doesn't exist."