如何否定流程的回报价值?

时间:2008-12-14 22:20:37

标签: shell cross-platform negate

我正在寻找一个简单但跨平台的否定 -process,它否定了流程返回的价值。它应该将0映射到某个值!= 0和任何值!= 0到0,即以下命令应该返回“yes,nonexistingpath不存在”:

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

! - 运算符很棒,但遗憾的是不依赖于shell。

7 个答案:

答案 0 :(得分:72)

以前,答案是在第一部分作为最后一部分提出的。

POSIX Shell包含!运算符

针对其他问题探讨shell规范,我最近(2015年9月)注意到POSIX shell支持!运算符。例如,它被列为reserved word并且可以出现在pipeline的开头 - 其中一个简单命令是“管道”的特例。因此,它也可以在if语句和whileuntil循环中使用 - 符合POSIX标准的shell。因此,尽管我有所保留,它可能比我在2008年意识到的更广泛。对POSIX 2004和SUS / POSIX 1997的快速检查表明!在这两个版本中都存在。

请注意,!运算符必须出现在管道的开头,并否定整个管道的状态代码(即 last 命令)。以下是一些例子。

# 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

这是便携式的。 “命令和参数”可以是管道或其他复合命令序列。

A not命令

'!'运算符,无论是内置于shell还是由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);
}

当它无法执行命令时,它返回'success',与失败相反。我们可以辩论“无所事事”选项是否正确;也许它应该在没有被要求做任何事情时报告错误。 “"stderr.h"”中的代码提供了简单的错误报告功能 - 我在任何地方都使用它。根据要求提供源代码 - 请参阅我的个人资料页面与我联系。

答案 1 :(得分:39)

在Bash中,使用!命令前的操作符。例如:

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

答案 2 :(得分:17)

你可以尝试:

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

或只是:

! ls nonexistingpath

答案 3 :(得分:9)

如果某种情况发生你没有Bash作为你的shell(例如:git脚本或puppet exec测试)你可以运行:

echo '! ls notexisting' | bash

- &GT; retcode:0

echo '! ls /' | bash

- &GT; retcode:1

答案 4 :(得分:2)

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

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

答案 5 :(得分:1)

不带!,不带subshel​​l,不带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."

答案 6 :(得分:0)

注意:有时您会看到!(command || other command)
这里! ls nonexistingpath && echo "yes, nonexistingpath doesn't exist."就足够了。
不需要子外壳。

Git 2.22(2019年第二季度)通过以下方式说明了更好的形式:

Commit 74ec8cfcommit 3fae7adcommit 0e67c32commit 07353d9commit 3bc2702commit 8c3b9f7commit 80a539acommit c5c39f4 (2019年3月13日)通过SZEDER Gábor (szeder)
请参见commit 99e37c2commit 9f82b2acommit 900721eJohannes Schindelin (dscho)(2019年3月13日)。
(由Junio C Hamano -- gitster --commit 579b75a中合并,2019年4月25日)

  

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'打印。
  这是有问题的,because according to POSIX

     
    

”如果流水线以保留字!开头并且command1是子shell命令,则应用程序应确保(开头的command1运算符为与!隔开一个或多个<blank>字符。
    未指定保留字!紧跟着(运算符的行为。

  
     

尽管大多数常见的shell仍将此“ !”解释为“否定退出   管道中最后一条命令的代码”,“ mksh/lksh”和   而是将其解释为否定文件名模式。
  结果,他们尝试运行由当前路径名组成的命令   目录(它包含一个名为“ main”的目录),其中   当然,测试失败。

     

我们可以简单地通过在“ !”和“ (”之间添加空格来解决此问题,但是   相反,让我们通过删除不必要的子外壳来修复它。   特别是Commit 74ec8cf