如何否定进程的返回值? [英] How can I negate the return-value of a process?
问题描述
我正在寻找一个简单但跨平台的否定-过程,它否定一个过程返回的值.它应该将 0 映射到某个值 != 0 和任何值 != 0 到 0,即以下命令应返回是的,不存在的路径不存在":
ls 不存在的路径 |否定&&echo "是的,不存在的路径不存在."
!- 运算符很棒,但不幸的是不是独立于外壳的.
以前,答案是用现在的第一部分作为最后一部分来呈现的.>
POSIX Shell 包含一个 !
操作符
针对其他问题仔细研究 shell 规范,我最近(2015 年 9 月)注意到 POSIX shell 支持 !
运算符.例如,它被列为保留字并且可以出现在管道的开头——其中一个简单的命令是管道"的特殊情况.因此,它也可以用在 if
语句和 while
或 until
循环中——在符合 POSIX 的 shell 中.因此,尽管我有所保留,但它可能比我在 2008 年意识到的更广泛使用.快速检查 POSIX 2004 和 SUS/POSIX 1997 表明 !
出现在这两个版本中.
注意!
操作符必须出现在管道的开始,并否定整个管道的状态码(即最后命令).以下是一些示例.
# 简单的命令、管道和重定向工作正常.$!some-command 成功;回声 $?1$!一些命令失败 |some-other-command 失败;回声 $?0$!一些命令 <成功.txt;回声 $?1# 环境变量也可以使用,但必须在 ! 之后.$!结果=失败某些命令;回声 $?0# 一个更复杂的例子.$如果!一些命令 <输入.txt |grep 成功 >/开发/空;然后回显'失败!';恢复命令;mv input.txt input-failed.txt;菲失败!$ ls *.txt输入失败.txt
便携式答案 - 使用古董贝壳
在 Bourne(Korn、POSIX、Bash)脚本中,我使用:
if ...命令和参数...然后:它成功了否则:失败菲
这非常便携.命令和参数"可以是管道或其他复合命令序列.
一个 not
命令
!"运算符,无论是内置于您的 shell 还是由 o/s 提供,都不是普遍可用的.不过,编写起来并不难——下面的代码至少可以追溯到 1991 年(尽管我认为我在更久以前编写了以前的版本).不过,我不倾向于在我的脚本中使用它,因为它不可靠.
/*@(#)File: $RCSfile: not.c,v $@(#)版本:$修订:4.2 $@(#)最后更改:$Date:2005/06/22 19:44:07 $@(#) 目的:反转命令的成功/失败状态@(#)作者:J Leffler@(#)版权:(C) JLSS 1991,1997,2005*/#include #include #include #include #include stderr.h"#ifndef 棉绒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;内部尸体;内部状态;err_setarg0(argv[0]);如果(argc <= 1){/* 没有什么要执行的.没有成功执行.*//* 反向退出条件非零 */退出(1);}如果 ((pid = fork()) <0)err_syserr(分叉失败
");如果(pid == 0){/* 子:使用 PATH 等执行命令 */execvp(argv[1], &argv[1]);err_syserr(无法执行命令 %s
", argv[1]);/* 还没到 */}/* 父母 */while ((尸体 = 等待(&status)) > 0){如果(尸体 == pid){/* 状态包含孩子的退出状态.*//* 如果孩子的退出状态为零,则成功,我们应该以非零状态退出 *//* 如果孩子的退出状态非零,如果失败,我们应该以零状态退出 */退出(状态== 0);/* 还没到 */}}/* 未能收到孩子死亡的通知——假设它失败了 */返回 (0);}
当它无法执行命令时,这将返回成功",与失败相反.我们可以争论什么都不做"选项是否正确;也许它应该在没有被要求做任何事情时报告错误.'"stderr.h"
' 中的代码提供了简单的错误报告工具——我到处都使用它.应要求提供源代码 - 请参阅我的个人资料页面以与我联系.
I'm looking for a simple, but cross-platform negate-process that negates the value a process returns. It should map 0 to some value != 0 and any value != 0 to 0, i.e. the following command should return "yes, nonexistingpath doesn't exist":
ls nonexistingpath | negate && echo "yes, nonexistingpath doesn't exist."
The ! - operator is great but unfortunately not shell-independent.
Previously, the answer was presented with what's now the first section as the last section.
POSIX Shell includes a !
operator
Poking around the shell specification for other issues, I recently (September 2015) noticed that the POSIX shell supports a !
operator. For example, it is listed as a reserved word and can appear at the start of a pipeline — where a simple command is a special case of 'pipeline'. It can, therefore, be used in if
statements and while
or until
loops too — in POSIX-compliant shells. Consequently, despite my reservations, it is probably more widely available than I realized back in 2008. A quick check of POSIX 2004 and SUS/POSIX 1997 shows that !
was present in both those versions.
Note that the !
operator must appear at the beginning of the pipeline and negates the status code of the entire pipeline (i.e. the last command). Here are some examples.
# 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
Portable answer — works with antique shells
In a Bourne (Korn, POSIX, Bash) script, I use:
if ...command and arguments...
then : it succeeded
else : it failed
fi
This is as portable as it gets. The 'command and arguments' can be a pipeline or other compound sequence of commands.
A not
command
The '!' operator, whether built-in to your shell or provided by the o/s, is not universally available. It isn't dreadfully hard to write, though - the code below dates back to at least 1991 (though I think I wrote a previous version even longer ago). I don't tend to use this in my scripts, though, because it is not reliably available.
/*
@(#)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
");
if (pid == 0)
{
/* Child: execute command using PATH etc. */
execvp(argv[1], &argv[1]);
err_syserr("failed to execute command %s
", 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);
}
This returns 'success', the opposite of failure, when it fails to execute the command. We can debate whether the 'do nothing successfully' option was correct; maybe it should report an error when it isn't asked to do anything. The code in '"stderr.h"
' provides simple error reporting facilities - I use it everywhere. Source code on request - see my profile page to contact me.
这篇关于如何否定进程的返回值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!