Как я могу отрицать возвращаемое значение процесса?

Я ищу простой, но кроссплатформенный процесс отрицания - отрицания, который сводит на нет значение, возвращаемое процессом. Он должен отображать 0 на какое-то значение!= 0 и любое значение!= 0 на 0, то есть следующая команда должна возвращать "да, не существует пути не существует":

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

! - оператор отличный, но, к сожалению, не зависит от оболочки.

5 ответов

Решение

Ранее ответ был представлен с тем, что сейчас является первым разделом в качестве последнего раздела.

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 команда

"!" Оператор, встроенный в вашу оболочку или предоставляемый o/s, не всегда доступен. Это не так сложно написать, хотя приведенный ниже код восходит по крайней мере к 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"предоставляет простые средства сообщения об ошибках - я использую его везде. Исходный код по запросу - смотрите страницу моего профиля, чтобы связаться со мной.

В Bash используйте! оператор перед командой. Например:

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

Вы можете попробовать:

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

или просто:

! ls nonexistingpath

Если как-то случится, что у вас нет Bash в качестве оболочки (например, git-скрипты или кукольные exec-тесты), вы можете запустить:

echo '! ls notexisting' | bash

-> Реткод: 0

echo '! ls /' | bash

-> Реткод: 1

Решение без!, Без подоболочки, без 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."
! ls nonexistingpath && echo "yes, nonexistingpath doesn't exist."

или же

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

Примечание: иногда вы увидите !(command || other command),
Вот ! ls nonexistingpath && echo "yes, nonexistingpath doesn't exist." достаточно.
Нет необходимости в под-оболочке.

Git 2.22 (Q2 2019) иллюстрирует эту лучшую форму с:

Зафиксируйте 74ec8cf, зафиксируйте 3fae7ad, зафиксируйте 0e67c32, зафиксируйте 07353d9, зафиксируйте 3bc2702, зафиксируйте 8c3b9f7, зафиксируйте 80a539a, зафиксируйте c5c39f4 (13 марта 2019 г.) от SZEDER Gábor ( szeder)
См. Коммит 99e37c2, коммит 9f82b2a, коммит 900721e (13 марта 2019 г.) от Johannes Schindelin ( dscho )
(Объединено Юнио С Хамано - gitster - в коммите 579b75a, 25 апреля 2019 г.)

t9811-git-p4-label-import: исправить отрицание конвейера

В ' t9811-git-p4-label-import.sh ', тест ' tag that cannot be exported 'работает:

!(p4 labels | grep GIT_TAG_ON_A_BRANCH)

проверить, что данная строка не напечатана p4 labels ".
Это проблематично, потому что согласно POSIX:

"Если конвейер начинается с зарезервированного слова ! а также command1 является командой subshell, приложение должно гарантировать, что ( оператор в начале command1 отделен от ! одним или несколькими <blank> персонажи.
Поведение зарезервированного слова ! сразу же после ( оператор не указан. "

В то время как большинство обычных оболочек все еще интерпретируют это ! 'as' отменить код выхода последней команды в конвейере ',' mksh/lksh 'не и интерпретировать его как отрицательный шаблон имени файла.
В результате они пытаются запустить команду, составленную из путей в текущем каталоге (он содержит один каталог с именем ' main '), что, конечно, не проходит проверку.

Мы могли бы это исправить, просто добавив пробел между ! ' а также ' ( ', но вместо этого давайте исправим это, удалив ненужную подоболочку. В частности, Commit 74ec8cf

Другие вопросы по тегам