Раньше ответ был представлен тем, что теперь первый раздел и последний раздел.
POSIX Shell включает !
оператор
Пробираясь по спецификации оболочки для решения других проблем, я недавно (сентябрь 2015 г.) заметил, что оболочка POSIX поддерживает !
оператор. Например, оно указано как зарезервированное слово и может появляться в начале конвейера, где простая команда является частным случаем «конвейера». Следовательно, его можно использовать в if
операторах и / while
или until
циклах - в POSIX-совместимых оболочках. Следовательно, несмотря на мои оговорки, он, вероятно, более доступен, чем я предполагал в 2008 году. Быстрая проверка POSIX 2004 и SUS / POSIX 1997 показывает, что они !
присутствовали в обеих этих версиях.
Обратите внимание, что !
оператор должен находиться в начале конвейера и отменяет код состояния всего конвейера (т.е. последнюю команду). Вот несколько примеров.
$ ! 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
Портативный ответ - работает со старинными ракушками
В сценарии Bourne (Korn, POSIX, Bash) я использую:
if ...command and arguments...
then : it succeeded
else : it failed
fi
Это настолько портативно, насколько это возможно. «Команда и аргументы» могут быть конвейером или другой составной последовательностью команд.
not
команда
Символ '!' Оператор, встроенный в оболочку или предоставляемый операционными системами, доступен не везде. Однако написать его не так уж и сложно - приведенный ниже код восходит как минимум к 1991 году (хотя я думаю, что предыдущую версию я написал еще раньше). Однако я не использую это в своих сценариях, потому что это ненадежно.
/*
@(
@(
@(
@(
@(
@(
*/
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);
}
Это возвращает «успех», противоположный провалу, когда не удается выполнить команду. Мы можем спорить, был ли вариант «ничего не делать успешно» был правильным; возможно, он должен сообщить об ошибке, когда его не просят что-либо сделать. Код в ' "stderr.h"
' предоставляет простые средства сообщения об ошибках - я использую его везде. Исходный код по запросу - см. Страницу моего профиля, чтобы связаться со мной.