1. ホーム
  2. shell

[解決済み] ある処理の戻り値を否定するには?

2022-08-17 19:36:46

質問

私は、シンプルでクロスプラットフォームな ネゲート -プロセスが返す値を否定するものを探しています。例えば、次のコマンドは "yes, nonexistingpath doesn't exist" を返すはずです。

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

演算子は素晴らしいものですが、残念ながらシェルに依存しないものです。

どのように解決するのですか?

以前は、現在の最初のセクションを最後のセクションとして答えを提示していました。

POSIX シェルには ! 演算子があります。

その他の問題でシェルの仕様を詮索していると、最近(2015年9月)、POSIXシェルがサポートする ! 演算子があることに気づきました。 例えば、リストアップされている 予約語 の先頭に表示され パイプライン - ここで、単純なコマンドは 'pipeline' の特殊なケースです。 したがって、これは 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

これは限りなくポータブルです。 コマンドと引数」は、パイプラインや他の複合的なコマンドのシーケンスにすることができます。

A not コマンド

演算子は、シェルに組み込まれているか OS によって提供されているかに関わらず、普遍的に利用できるものではありません。 以下のコードは少なくとも 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" のコードは簡単なエラー報告機能を提供します。 ソースコードのリクエストは、私のプロフィールページで受け付けています。