Szukam prostego, ale wieloplatformowego procesu negacji, który neguje wartość zwracaną przez proces. Powinien odwzorować 0 na jakąś wartość! = 0 i dowolną wartość! = 0 na 0, tj. Poniższe polecenie powinno zwrócić „tak, nieistniejąca ścieżka nie istnieje”:
ls nonexistingpath | negate && echo "yes, nonexistingpath doesn't exist."
The! - operator jest świetny, ale niestety nie jest niezależny od powłoki.
shell
cross-platform
negate
secr
źródło
źródło
Odpowiedzi:
Wcześniej odpowiedź była przedstawiana jako ostatnia sekcja, która jest teraz pierwszą sekcją.
POSIX Shell zawiera
!
operatorPrzeglą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 wif
instrukcjach i /while
lubuntil
pę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.# 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
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ń.
not
komendaZnak '!' 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.
/* @(#)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 <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #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); }
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ć.źródło
!
operatorze. To zadziałało dla mnie:! MY_ENV=value my_command
ldd foo.exe | ! grep badlib
ale możesz to zrobić,! ldd foo.exe | grep badlib
jeśli chcesz, aby kod zakończenia wynosił 0, jeśli badlib nie zostanie znaleziony w foo.exe. Semantycznie chcesz odwrócićgrep
stan, ale odwrócenie całej potoku daje ten sam wynik.ldd foo.exe | { ! grep badlib; }
(choć jest to uciążliwe, zwłaszcza średnik; można użyć pełnej sub-shell z(
i)
bez średnika). OTOH, obiekt ma odwrócić status wyjścia potoku, a to jest status wyjścia ostatniego polecenia (z wyjątkiem czasami Bash).!
komenda ma niepożądanej interakcji zset -e
, czyli powoduje, że komenda do osiągnięcia sukcesu z kodem 0 lub niezerowe wyjścia, zamiast kolejny tylko z niezerowym kodem wyjścia. Czy istnieje zwięzły sposób, aby odnieść sukces tylko z niezerowym kodem zakończenia?W Bash użyj! operator przed poleceniem. Na przykład:
! ls nonexistingpath && echo "yes, nonexistingpath doesn't exist"
źródło
Możesz spróbować:
ls nonexistingpath || echo "yes, nonexistingpath doesn't exist."
Lub tylko:
źródło
!
nie można z nim korzystaćgit bisect run
, a przynajmniej nie wiem jak.!
w tym przypadku.Jeśli w jakiś sposób zdarzy się, że nie masz Bash jako powłoki (np. Skrypty git lub testy Puppet exec), możesz uruchomić:
echo '! ls notexisting' | bash
-> retcode: 0
echo '! ls /' | bash
-> retcode: 1
źródło
! ls nonexistingpath && echo "yes, nonexistingpath doesn't exist."
lub
ls nonexistingpath || echo "yes, nonexistingpath doesn't exist."
źródło
$?
będzie inna. Pierwszy może odejść,$?=1
jeślinonexistingpath
rzeczywiście istnieje. Drugi zawsze odchodzi$?=0
. Jeśli używasz tego w pliku Makefile i musisz polegać na wartości zwracanej, musisz być ostrożny.Uwaga: czasami zobaczysz
!(command || other command)
.Tutaj
! ls nonexistingpath && echo "yes, nonexistingpath doesn't exist."
wystarczy.Nie ma potrzeby stosowania podpowłoki.
Git 2.22 (Q2 2019) ilustruje tę lepszą formę z:
Zatwierdzić 74ec8cf , zatwierdzić 3fae7ad , zatwierdzić 0e67c32 , zatwierdzić 07353d9 , zatwierdzić 3bc2702 , zatwierdzić 8c3b9f7 , zatwierdzić 80a539a , zatwierdzić c5c39f4 (13 marca 2019) przez SZEDER Gábor (
szeder
) .Zobacz commit 99e37c2 , commit 9f82b2a , commit 900721e (13 marca 2019) autorstwa Johannes Schindelin (
dscho
) .(Scalone przez Junio C Hamano -
gitster
- w zobowiązaniu 579b75a , 25 kwietnia 2019 r.)źródło
Rozwiązanie bez!, Bez podpowłoki, bez if i powinno działać przynajmniej w bash:
ls nonexistingpath; test $? -eq 2 && echo "yes, nonexistingpath doesn't exist." # alternatively without error message and handling of any error code > 0 ls nonexistingpath 2>/dev/null; test $? -gt 0 && echo "yes, nonexistingpath doesn't exist."
źródło