Я ищу простой, но кроссплатформенный процесс отрицания, который отрицает значение, возвращаемое процессом. Он должен отображать 0 в какое-то значение! = 0 и любое значение! = 0 в 0, то есть следующая команда должна возвращать «да, несуществующий путь не существует»:
ls nonexistingpath | negate && echo "yes, nonexistingpath doesn't exist."
! - оператор отличный, но, к сожалению, не зависит от оболочки.
Ответы:
Раньше ответ был представлен тем, что теперь первый раздел и последний раздел.
POSIX Shell включает
!
операторПробираясь по спецификации оболочки для решения других проблем, я недавно (сентябрь 2015 г.) заметил, что оболочка POSIX поддерживает
!
оператор. Например, оно указано как зарезервированное слово и может появляться в начале конвейера, где простая команда является частным случаем «конвейера». Следовательно, его можно использовать вif
операторах и /while
илиuntil
циклах - в POSIX-совместимых оболочках. Следовательно, несмотря на мои оговорки, он, вероятно, более доступен, чем я предполагал в 2008 году. Быстрая проверка POSIX 2004 и SUS / POSIX 1997 показывает, что они!
присутствовали в обеих этих версиях.Обратите внимание, что
!
оператор должен находиться в начале конвейера и отменяет код состояния всего конвейера (т.е. последнюю команду). Вот несколько примеров.# 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
Портативный ответ - работает со старинными ракушками
В сценарии Bourne (Korn, POSIX, Bash) я использую:
if ...command and arguments... then : it succeeded else : it failed fi
Это настолько портативно, насколько это возможно. «Команда и аргументы» могут быть конвейером или другой составной последовательностью команд.
not
командаСимвол '!' Оператор, встроенный в оболочку или предоставляемый операционными системами, доступен не везде. Однако написать его не так уж и сложно - приведенный ниже код восходит как минимум к 1991 году (хотя я думаю, что предыдущую версию я написал еще раньше). Однако я не использую это в своих сценариях, потому что это ненадежно.
/* @(#)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); }
Это возвращает «успех», противоположный провалу, когда не удается выполнить команду. Мы можем спорить, был ли вариант «ничего не делать успешно» был правильным; возможно, он должен сообщить об ошибке, когда его не просят что-либо сделать. Код в '
"stderr.h"
' предоставляет простые средства сообщения об ошибках - я использую его везде. Исходный код по запросу - см. Страницу моего профиля, чтобы связаться со мной.источник
!
оператором. У меня это сработало:! MY_ENV=value my_command
ldd foo.exe | ! grep badlib
но можете сделать,! ldd foo.exe | grep badlib
если хотите, чтобы статус выхода был равен 0, если badlib не найден в foo.exe. Семантически вы хотите инвертироватьgrep
статус, но инвертирование всей трубы дает тот же результат.ldd foo.exe | { ! grep badlib; }
(хотя это неудобство, особенно точка с запятой, вы можете использовать полную подоболочку с(
и)
без точки с запятой). OTOH, цель состоит в том, чтобы инвертировать статус выхода конвейера, и это статус выхода последней команды (за исключением Bash, иногда).!
команда имеет нежелательное взаимодействие сset -e
, т.е. вызывает команду , чтобы добиться успеха с кодом 0 или ненулевая выхода, а сменив только с кодом ненулевым. Есть ли краткий способ добиться успеха только с ненулевым кодом выхода?В Bash используйте! оператор перед командой. Например:
! ls nonexistingpath && echo "yes, nonexistingpath doesn't exist"
источник
Вы можете попробовать:
ls nonexistingpath || echo "yes, nonexistingpath doesn't exist."
или просто:
источник
!
нельзя использоватьgit bisect run
, по крайней мере, я не знаю как.!
в этом случае не видит .Если каким-то образом случится так, что у вас нет Bash в качестве оболочки (например, скрипты git или тесты puppet exec), вы можете запустить:
echo '! ls notexisting' | bash
-> retcode: 0
echo '! ls /' | bash
-> retcode: 1
источник
! ls nonexistingpath && echo "yes, nonexistingpath doesn't exist."
или
ls nonexistingpath || echo "yes, nonexistingpath doesn't exist."
источник
$?
будет другим. Первый может уйти,$?=1
еслиnonexistingpath
он действительно существует. Второй всегда уходит$?=0
. Если вы используете это в Makefile и вам нужно полагаться на возвращаемое значение, вы должны быть осторожны.Примечание: иногда вы увидите
!(command || other command)
.Здесь
! ls nonexistingpath && echo "yes, nonexistingpath doesn't exist."
достаточно.Нет необходимости в дополнительной оболочке.
Git 2.22 (второй квартал 2019 г.) иллюстрирует эту лучшую форму с помощью:
Зафиксировать 74ec8cf , зафиксировать 3fae7ad , зафиксировать 0e67c32 , зафиксировать 07353d9 , зафиксировать 3bc2702 , зафиксировать 8c3b9f7 , зафиксировать 80a539a , зафиксировать c5c39f4 (13 марта 2019 г.) от SZEDER Gábor (
szeder
) .См. Commit 99e37c2 , commit 9f82b2a , commit 900721e (13 марта 2019 г.) Йоханнеса Шинделина (
dscho
) .(Объединено Junio C Hamano -
gitster
- в коммите 579b75a , 25 апреля 2019 г.)источник
Решение без!, Без подоболочки, без if и должно работать как минимум в 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."
источник