Wcześniej odpowiedź była przedstawiana jako ostatnia sekcja, która jest teraz pierwszą sekcją.
POSIX Shell zawiera !operator
Przeglądając specyfikację powłoki pod kątem innych problemów, niedawno (wrzesień 2015) zauważyłem, że powłoka POSIX obsługuje !operatora. Na przykład jest wymieniony jako słowo zastrzeżone i może pojawić się na początku potoku - gdzie proste polecenie jest specjalnym przypadkiem „potok”. Dlatego może być używany w ifinstrukcjach i / whilelub untilpętlach - w powłokach zgodnych z POSIX. W konsekwencji, pomimo moich zastrzeżeń, jest prawdopodobnie szerzej dostępny, niż zdawałem sobie sprawę w 2008 roku. Szybkie sprawdzenie POSIX 2004 i SUS / POSIX 1997 pokazuje, że !był obecny w obu tych wersjach.
Zauważ, że !operator musi pojawić się na początku potoku i zanegować kod statusu całego potoku (tj. Ostatnie polecenie). Oto kilka przykładów.
$ ! some-command succeed; echo $?
1
$ ! some-command fail | some-other-command fail; echo $?
0
$ ! some-command < succeed.txt; echo $?
1
$ ! RESULT=fail some-command; echo $?
0
$ 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
Przenośna odpowiedź - działa z antycznymi muszlami
W skrypcie Bourne'a (Korn, POSIX, Bash) używam:
if ...command and arguments...
then : it succeeded
else : it failed
fi
To jest tak przenośne, jak to tylko możliwe. „Polecenie i argumenty” może być potokiem lub inną złożoną sekwencją poleceń.
notkomenda
Znak '!' Operator, niezależnie od tego, czy jest wbudowany w twoją powłokę, czy dostarczany przez O / S, nie jest powszechnie dostępny. Nie jest jednak strasznie trudno napisać - poniższy kod pochodzi przynajmniej z 1991 roku (choć myślę, że poprzednią wersję napisałem nawet wcześniej). Nie używam tego jednak w moich skryptach, ponieważ nie jest to niezawodnie dostępne.
/*
@(
@(
@(
@(
@(
@(
*/
static const char sccs[] = "@(#)$Id: not.c,v 4.2 2005/06/22 19:44:07 jleffler Exp $";
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);
}
Zwraca „sukces”, przeciwieństwo niepowodzenia, gdy nie wykonuje polecenia. Możemy debatować, czy opcja „nic nie rób z powodzeniem” była słuszna; może powinien zgłosić błąd, gdy nie jest proszony o nic. Kod w „ "stderr.h"” zapewnia proste narzędzia do raportowania błędów - używam go wszędzie. Kod źródłowy na życzenie - zobacz moją stronę profilu, aby się ze mną skontaktować.