如何取消进程的返回值?

我正在寻找一个简单的,但是跨平台的 否定进程,它否定一个进程返回的值。它应该将0映射到某个值!= 0和任何值!= 0到0,也就是说,下面的命令应该返回“是的,不存在路径”:

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

!-操作符很棒,但不幸的是它不是与 shell 无关的。

55175 次浏览

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

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

你可以试试:

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

或者只是:

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

或者

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

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

POSIX Shell 包含一个 !操作符

我最近(2015年9月)在研究 shell 规范的其他问题时注意到,POSIX shell 支持 !操作符。例如,它被列为 保留意见,并且可以出现在 管道的开头ーー其中一个简单的命令是“管道”的特殊情况。因此,它可以在 if语句中使用,也可以在符合 POSIX 的 shell 中使用 whileuntil循环。因此,尽管我有所保留,但它可能比我在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指令

那个运算符,无论是内置到您的 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);
}

当执行命令失败时,返回“成功”,与失败相反。我们可以讨论“什么都不做”选项是否正确; 也许它应该在没有被要求做任何事情时报告一个错误。“ "stderr.h"”中的代码提供了简单的错误报告工具——我在任何地方都使用它。请求源代码-看我的个人资料页面联系我。

如果不知何故没有使用 Bash 作为 shell (例如: Git 脚本或 木偶 exec 测试) ,那么可以运行:

echo '! ls notexisting' | bash

- > 重新编码: 0

echo '! ls /' | bash

- > 重新编码: 1

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

Git 2.22(2019年第二季度)说明了更好的形式:

通过 赛德尔加博尔(szeder)提交74ec8cf ,犯罪犯罪现场调查,第六季,第32集提交07353d9提交3bc2702提交8c3b9f7犯下80a539a提交 c5c39f4(2019年3月13日)。
第九季,第37集提交9f82b2a提交900721e(2019年3月13日) by 约翰内斯 · 辛德林(dscho)
(由 朱尼奥 · C · 哈马诺 gitster于2019年4月25日在 犯下579b75a合并)

修复管道否定

在“ t9811-git-p4-label-import.sh”中,测试“ tag that cannot be exported”运行:

!(p4 labels | grep GIT_TAG_ON_A_BRANCH)

检查给定的字符串是否由“ p4 labels”打印。
这是有问题的,因为根据 < strong > POSIX :

”如果管道以保留字 !开头,而 command1是子 shell 命令,则应用程序应确保 command1开头的 (操作符与 !之间隔开一个或多个 <blank>字符。
紧跟在 (操作符后面的保留字 !的行为是未指定的

虽然大多数常见的 shell 仍然将这个“ !”解释为“否定退出 管道中最后一个命令的代码”,‘ mksh/lksh’不要和 而是将其解释为负文件名模式。
因此,它们尝试运行由当前 目录(它包含一个名为‘ main’的单一目录) 当然,考试不及格。

我们可以简单地通过在‘ !’和‘ (’之间添加一个空格来修复它,但是 相反,让我们通过删除不必要的 subshell 来修复它。 特别是,提交74ec8cf6747a60885e15d4c36e6b47bc37764748”rel = “ nofollow noReferrer”> Commit 74ec8cf

没有! 、没有 subshell、没有 if 的解决方案,并且应该至少在 Bash 中可以工作:

ls nonexistingpath; test $? -eq 2 && echo "yes, nonexistingpath doesn't exist."


# Alternatively without an error message and handling of any error code > 0
ls nonexistingpath 2>/dev/null; test $? -gt 0 && echo "yes, nonexistingpath doesn't exist."