[comp.unix.questions] How do I ask "if NOT" in shell?

kirkaas@oahu.cs.ucla.edu (paul kirkaas) (10/23/89)

How can one say "if not" in a shellscript; that is, execute the body of
the "then" only if the argument of "if" returns a non-zero exit status?

I would like something like:

if ! TESTCOMMAND
then
	BODY
fi

Stupid question?   Trivial answer?   I hope so.  Thanks.


Paul Kirkaas
kirkaas@cs.ucla.edu

maart@cs.vu.nl (Maarten Litmaath) (10/24/89)

kirkaas@oahu.cs.ucla.edu (paul kirkaas) writes:
\How can one say "if not" in a shellscript; that is, execute the body of
\the "then" only if the argument of "if" returns a non-zero exit status?

Unfortunately there doesn't seem to be a clean way to do this.
The obvious work-around:

	if command
	then
		:
	else
		command
	fi

A cleaner approach:

	if not command
	then
		command
	fi

...where `not' is defined as the following shell function/script:

	${1+"$@"}
	test $? != 0

SunOS 4.0.3c /bin/sh doesn't like a function to be named `!', a shell
script would be OK though.
-- 
A symbolic link is a POINTER to a file, | Maarten Litmaath @ VU Amsterdam:
 a hard link is the file system's GOTO. | maart@cs.vu.nl, mcsun!botter!maart

merlyn@iwarp.intel.com (Randal Schwartz) (10/24/89)

In article <28381@shemp.CS.UCLA.EDU>, kirkaas@oahu (paul kirkaas) writes:
| How can one say "if not" in a shellscript; that is, execute the body of
| the "then" only if the argument of "if" returns a non-zero exit status?
| 
| I would like something like:
| 
| if ! TESTCOMMAND
| then
| 	BODY
| fi
| 
| Stupid question?   Trivial answer?   I hope so.  Thanks.

Yeah.

if TESTCOMMAND
then
	: nada
else
	BODY
fi

Easy.

Just another Bourne-again hacker,
-- 
/== Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ====\
| on contract to Intel's iWarp project, Hillsboro, Oregon, USA, Sol III  |
| merlyn@iwarp.intel.com ...!uunet!iwarp.intel.com!merlyn	         |
\== Cute Quote: "Welcome to Oregon... Home of the California Raisins!" ==/

hitz@auspex.auspex.com (Dave Hitz) (10/24/89)

In article <28381@shemp.CS.UCLA.EDU> kirkaas@oahu.UUCP (paul kirkaas) writes:
>How can one say "if not" in a shellscript; that is, execute the body of
>the "then" only if the argument of "if" returns a non-zero exit status?
>
>I would like something like:
>
>if ! TESTCOMMAND
>then
>	BODY
>fi

I often define the following in my shell scripts.

	    NOT() {
		if ${1+"$@"}
		then return 1;
		else return 0;
		fi
	    }

Unfortunately, not all shells support functions yet, but for those that
do this works fine.  You can use this just like you requested:

	    if NOT grep foobar /etc/passwd >&-
	    then
		    BODY
	    fi

Picky people may observe that the arguments to NOT get expanded by
the shell twice, but I've never been caught by this.

-- 
Dave Hitz					home: 408-739-7116
UUCP: {uunet,mips,sun,bridge2}!auspex!hitz 	work: 408-970-8970

ag@cbmvax.UUCP (Keith Gabryelski) (10/24/89)

In article <3787@solo6.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
>kirkaas@oahu.cs.ucla.edu (paul kirkaas) writes:
>\How can one say "if not" in a shellscript; that is, execute the body of
>\the "then" only if the argument of "if" returns a non-zero exit status?

It is actually a toss up for me between:

>	if not command
>	then
>		command
>	fi
>
>...where `not' is defined as the following shell function/script:
>
>	${1+"$@"}
>	test $? != 0

and

	until command
	do
	    :				# do some stuff
	    break			# explict break
	done

Agreed that there should be a cleaner way.

Pax, Keith
-- 
 "It took no computation to dance to the rock 'n roll station" -- VU
  ag@cbmvax.commodore.com     Keith M. Gabryelski      ...!uunet!cbmvax!ag

ok@cs.mu.oz.au (Richard O'Keefe) (10/24/89)

When you really want to write
	unless command ; then
	    stmts
	fi
you can do it by writing
	command
	if test $? != 0 ; then # command failed
	    stmts
	fi

If stmts is sufficiently simple, you can also do
	command || { stmts }

mrm@sceard.Sceard.COM (M.R.Murphy) (10/24/89)

>kirkaas@oahu.cs.ucla.edu (paul kirkaas) writes:
>How can one say "if not" in a shellscript; that is, execute the body of
>the "then" only if the argument of "if" returns a non-zero exit status?

Might be a Good Thing to look up how && and || work, especially with { and }.
--
Mike Murphy  Sceard Systems, Inc.  544 South Pacific St. San Marcos, CA  92069
mrm@Sceard.COM        {hp-sdd,nosc,ucsd,uunet}!sceard!mrm      +1 619 471 0655

steinbac@hpl-opus.HP.COM (Gunter Steinbach) (10/25/89)

I prefer This form:

TESTCOMMAND || {
	BODY
	}

It doesn't allow an "else" clause, though.

roe@sobmips.UUCP (r.peterson) (10/25/89)

From article <2558@auspex.auspex.com>, by hitz@auspex.auspex.com (Dave Hitz):
> In article <28381@shemp.CS.UCLA.EDU> kirkaas@oahu.UUCP (paul kirkaas) writes:
>>How can one say "if not" in a shellscript; that is, execute the body of
>>the "then" only if the argument of "if" returns a non-zero exit status?
>>
>>I would like something like:
>>
>>if ! TESTCOMMAND
>>then
>>	BODY
>>fi
> 
> I often define the following in my shell scripts.

[function deleted]

> Unfortunately, not all shells support functions yet, but for those that
> do this works fine.  You can use this just like you requested:
> 
> 	    if NOT grep foobar /etc/passwd >&-
> 	    then
> 		    BODY
> 	    fi
> 

how about:

TESTCOMMAND
if [ ! $? -eq 0 ]
then
	BODY
fi

ie:

grep foobar /etc/passwd >/dev/null 2>&1
if [ ! $? -eq 0 ]    OR:   if test ! $? -eq 0
then
	BODY
fi
-- 
If the brain were so simple we understood it|Roe Peterson
We would be so simple we couldn't.          |{attcan,mcgill-vision}!sobeco!roe

roe@sobmips.UUCP (r.peterson) (10/26/89)

From article <63720010@hpl-opus.HP.COM>, by steinbac@hpl-opus.HP.COM (Gunter Steinbach):
> I prefer This form:
> 
> TESTCOMMAND || {
> 	BODY
> 	}
> 
> It doesn't allow an "else" clause, though.

I tried this:

true && {
	echo true
} || {
	echo false
}

and it functions fine.  Change true && to false && and it prints false
correctly as well.

-- 
If the brain were so simple we understood it|Roe Peterson
We would be so simple we couldn't.          |{attcan,mcgill-vision}!sobeco!roe

steinbac@hpl-opus.HP.COM (Gunter Steinbach) (10/27/89)

From article <1989Oct26.041244.28325@sobmips.UUCP>, by roe@sobmips.UUCP
(r.peterson):
> I tried this:
> true && {
> 	echo true
> } || {
> 	echo false
> }
> and it functions fine.  Change true && to false && and it prints false
> correctly as well.

Neato!  I like it.  
But...  You have to be careful with nontrivial commands in the first
command group (the if true group):  Add a "false" command after the
first echo in your example, and it prints out both "true" and "false" -
not at all what you wanted.

So it is not a true "else" that only refers to the original test.

	 Guenter Steinbach	 |	 hplabs!gunter_steinbach
				 |	 gunter_steinbach@hplabs.hp.com

maart@cs.vu.nl (Maarten Litmaath) (10/27/89)

roe@sobmips.UUCP (r.peterson) writes:
\...
\true && {
\	echo true
\} || {
\	echo false
\}
\
\and it functions fine.  Change true && to false && and it prints false
\correctly as well.

The abovementioned method has different characteristics:

	test-command && {
		if-clause
	} || {
		else-clause
	}

...will execute the else-clause if the test-command *or* the if-clause fails,
which might not be what you want.
-- 
A symbolic link is a POINTER to a file, | Maarten Litmaath @ VU Amsterdam:
 a hard link is the file system's GOTO. | maart@cs.vu.nl, mcsun!botter!maart

chip@ateng.com (Chip Salzenberg) (10/28/89)

Several people, including Dave Hitz, suggest variations on:

    NOT() {
	${1+"$@"}
	test $? -ne 0
    }

I love it!  It's simple and it works.  However, Dave Hitz asserts:

>Picky people may observe that the arguments to NOT get expanded by
>the shell twice, but I've never been caught by this.

In fact, they do not get expanded twice.  The effect of "$@", as opposed to
"$*", is to expand the shell function's arguments as if they were
_individually_ quoted.  Thus they will not be expanded (again) in the shell
function.

Unfortunately, if $# is zero, "$@" expands to "" instead of nothing.  Thus
the need for the ${1+"$@"} hack.  [sigh]
-- 
You may redistribute this article only to those who may freely do likewise.
Chip Salzenberg at A T Engineering;  <chip@ateng.com> or <uunet!ateng!chip>
"'Why do we post to Usenet?'  Naturally, the answer is, 'To get a response.'"
                        -- Brad "Flame Me" Templeton