我正在寻找一个简单但跨平台的否定-process,它否定一个进程返回的值。它应该将0映射到某个值!= 0,将任何值!= 0映射到0,即以下命令应返回“是,不存在的路径不存在”:
ls nonexistingpath | negate && echo "yes, nonexistingpath doesn't exist."
!-运算符很棒,但不幸的是不是独立于shell的。
我正在寻找一个简单但跨平台的否定-process,它否定一个进程返回的值。它应该将0映射到某个值!= 0,将任何值!= 0映射到0,即以下命令应返回“是,不存在的路径不存在”:
ls nonexistingpath | negate && echo "yes, nonexistingpath doesn't exist."
!-运算符很棒,但不幸的是不是独立于shell的。
Answers:
以前,答案是第一部分,最后一部分。
!
运算符围绕外壳规范中的其他问题,我最近(2015年9月)注意到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"
”中的代码提供了简单的错误报告功能-我到处都使用它。根据要求提供源代码-请参阅我的个人资料页面与我联系。
!
运算符。这对我! MY_ENV=value my_command
ldd foo.exe | ! grep badlib
,但你可以做! ldd foo.exe | grep badlib
,如果你想退出状态是0,如果badlib是不是在foo.exe的发现。在语义上,您想反转grep
状态,但是反转整个管道会得到相同的结果。
您可以尝试:
ls nonexistingpath || echo "yes, nonexistingpath doesn't exist."
要不就:
! ls nonexistingpath
!
不能与一起使用git bisect run
,或者至少我不知道如何使用。
!
在这种情况下看不到。
! 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(2019年3月13日)通过SZEDERGábor(szeder
)。
请参阅Johannes Schindelin()的提交99e37c2,提交9f82b2a和提交900721e(2019年3月13日)。(通过合并JUNIOÇ滨野- -在提交579b75a,2019年4月25日)dscho
gitster
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
是子shell命令,则应用程序应确保(
操作符的开头与字符之间用一个或多个字符command1
分隔。未指定保留字的行为,紧随操作符之后。 ”!
<blank>
!
(
尽管大多数常见的shell仍将此解释
!
为“'使管道中最后一个命令的退出代码mksh/lksh
无效”,但不要将其解释为负文件名模式。
结果,他们尝试运行由当前目录中的路径名组成的命令(该路径名包含一个名为'main
'的目录),该命令当然会通过测试。我们可以通过在'
!
'和'(
'之间添加一个空格来简单地对其进行修复,而让我们通过删除不必要的subshell来对其进行修复。特别是,提交74ec8cf
没有!,没有subshell,没有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."