[net.unix] question-- Bourne

arturo@humming.UUCP (Arturo Perez) (08/14/86)

Here's something I've wanted to do for a while but I can't seem to find the
way to do it.

In the csh you can do something like

ls foo
if (! $status) then
   echo "foo exists"
endif

The  key  thing  here  is  the  ability  to NOT the value of status. How is
this similar thing done in Bourne shell.

if ! ls foo
then
	echo foo does not exist
fi

In  summary,  how can I take the logical NOT of a command's return value in
the Bourne shell (which is God's gift to U**X :-)?
-- 
"Life is but a dream" - Lope de Vega
    "...for some and a NIGHTMARE for others!" Merlin, "Excalibur", the movie
Disclaimer?  What disclaimer?  I can back everything up with as much 
drivel as you like!

gwyn@brl-smoke.ARPA (Doug Gwyn ) (08/16/86)

In article <150@humming.UUCP> arturo@humming.UUCP (Arturo Perez) writes:
>In  summary,  how can I take the logical NOT of a command's return value in
>the Bourne shell (which is God's gift to U**X :-)?

Here is how the .funcs function-definition file I source from my .profile
does it:

not(){	$*
	if [ $? -eq 0 ]
	then	return 1
	else	return 0
	fi
}

So I can then use this new "not" command as in:
	if not stuff ...
	then	whatever
	fi

Another more direct trick is:
	if stuff ...
	then	:
	else	whatever
	fi

guy@sun.uucp (Guy Harris) (08/16/86)

> The  key  thing  here  is  the  ability  to NOT the value of status. How is
> this similar thing done in Bourne shell.
> 
> if ! ls foo
> then
> 	echo foo does not exist
> fi

Try

	if ls foo
	then
		:
	else
		echo foo does not exist
	fi

The ":"  is the pseudo-comment from old Bourne shells; it's really a command
that does nothing.

Not the cleanest syntax, but that's life.  (However, I'd rather have a shell
that requires that crud, but allows you to redirect the output of a "for"
loop, than one that permits you to negate exit status directly but won't let
you redirect the output of loops!  At least with the Bourne shell you can
get around the inability to negate exit status fairly easily.)

However, you may be better off doing

	if test ! -f foo

or something like that; unfortunately, "test" doesn't have a predicate for
"just test whether it exists", but you may really want a more restrictive
predicate anyway.
-- 
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com (or guy@sun.arpa)

dce@mips.UUCP (David Elliott) (08/16/86)

In article <150@humming.UUCP> arturo@humming.UUCP (Arturo Perez) writes:
>Here's something I've wanted to do for a while but I can't seem to find the
>way to do it.
>
>In the csh you can do something like
>
>ls foo
>if (! $status) then
>   echo "foo exists"
>endif
>
>The  key  thing  here  is  the  ability  to NOT the value of status. How is
>this similar thing done in Bourne shell.
>

Wrong. The key thing here is the ability to evaluate an expression. Though
not built in to most versions of sh, the 'test' command can be used for a
similar effect, as can 'expr', and you can always use 'case'.

Here are three ways:

1. The 'test' command (this also exists as '[' in many systems, so I'll use
   that here)

	ls foo
	if [ $? -eq 0 ]
	then
		echo "exists"
	fi

2. The 'expr' command (since this prints the boolean truth value, we throw
   the output away)

	ls foo
	if expr $? != 0 >/dev/null
	then
		echo "exists"
	fi

3. The 'case' statement

	ls foo
	case "$?" in
		0)
			echo "exists"
			;;
	esac

There are two problems with this:

	1. You have programmed-in knowledge that '0' is 'true' (this isn't
	   really so bad).
	2. If 'foo' doesn't exist, 'ls' may still exit with a 0. A quick look
	   at the 4.3BSD code proves me out.

What is really needed here is what Guy Harris suggested, which is:

	if [ -f foo ]
	then
		echo "exists"
	fi

except that '[ -f foo ]' only returns true if 'foo' is a regular file.

This brings up a couple of really strange (but valid) examples:

	case `echo foo*` in
		"foo" | "foo "*)
			echo "exists"
			;;
	esac


	# 'dummy' ensures proper 'for' syntax
	for i in foo* dummy
	{
		case "$i" in
			"foo")
				echo "exists"
				break
				;;
		esac
	}

(Excuse the prodigious use of quotes. I'm a "fanatic".)

			David Elliott
			{ucbvax,decvax,ihnp4}!decwrl!mips!dce

levy@ttrdc.UUCP (Daniel R. Levy) (08/17/86)

In article <150@humming.UUCP>, arturo@humming.UUCP (Arturo Perez) writes:
>In the csh you can do something like
>
>ls foo
>if (! $status) then
>   echo "foo exists"
>endif
>
>The  key  thing  here  is  the  ability  to NOT the value of status. How is
>this similar thing done in Bourne shell.
>
>if ! ls foo
>then
>	echo foo does not exist
>fi

To follow your example literally:

ls foo
if test $? -ne 0	# or, "if [ $? -ne 0 ]" is supported by modern /bin/sh's
then
	echo foo does not exist
fi

Of course, there are other ways to check for nonexistence of foo, e.g.:

if [ ! -f foo -a ! -d foo -a ! -p foo -a ! -c foo -a ! -b foo ]

# foo is not a file, a directory, a pipe, a character special device, or a
# block special device

which though "wordier" does not require the spawning of another process
presuming that "test" is a builtin in your shell.
-- 
 -------------------------------    Disclaimer:  The views contained herein are
|       dan levy | yvel nad      |  my own and are not at all those of my em-
|         an engihacker @        |  ployer or the administrator of any computer
| at&t computer systems division |  upon which I may hack.
|        skokie, illinois        |
 --------------------------------   Path: ..!{akgua,homxb,ihnp4,ltuxa,mvuxa,
	   go for it!  			allegra,ulysses,vax135}!ttrdc!levy

chris@pixutl.UUCP (chris) (08/18/86)

You can also do:

	( ls foo ) || echo not there

or, more cheaply:

	{ ls foo ; } || echo not there

and if you didn't want to see the output of the ls command,

	{ ls foo >/dev/null 2>&1 ; } || echo not there



Chris
-- 

 Chris Bertin       :  (603) 881-8791 x218
 xePIX Inc.         :
 51 Lake St         :  {allegra|ihnp4|cbosgd|ima|genrad|amd|harvard}\
 Nashua, NH 03060   :     !wjh12!pixel!pixutl!chris

arturo@humming.UUCP (Arturo Perez) (08/20/86)

In article <??.arturo@humming.uucp> arturo@humming.UUCP writes:
>> The  key  thing  here  is  the  ability  to NOT the value of status. How is
>> this similar thing done in Bourne shell.
>> 
>> if ! ls foo
>> then
>> 	echo foo does not exist
>> fi
>
>Try
>
>	if ls foo
>	then
>		:
>	else
>		echo foo does not exist
>	fi
>
>However, you may be better off doing
>
>	if test ! -f foo
>
>	Guy Harris
>	guy@sun.com (or guy@sun.arpa)

[Also suggested by Chris Torek <..!seismo!mimsy.umd.edu!umcp-cs!chris>,
harvard!g.cs.cmu.edu!Bennet.Yee, Stu Heiss <..!ihnp4!jpusa1!stu>,
and David Harrison <harvard!seismo!mnetor!utfyzx!harrison>]

I guess I confused everyone. What I meant was I wanted a method to directly
not  the status of a command in an if statement. I don't want to single Guy
out  but  his  answer  was  typical of the response I got (much more nicely
worded than some, too). Here are some more:

>From seismo!rick
From: Rick Adams <harvard!seismo!rick>

$? is equivalent to $status. test it the same way you did in csh


>From caip!princeton!allegra!ho95e!wcs

Look at the man pages for test(1) and sh(1), in particular the
sections on standard variables.  $? is the return code of the previous
command, so you can say
	foo
	if [ "$?" != 0 ]
		then echo "no foo"
		else echo "foo worked"
		fi

On most Bourne shell versions, and ksh, test is usually a built-in, and
"[" is a built-in alias for test.  You can't say 
	if [ ! "$?" ]
because that means "if "$?" is not empty-string", and $? always has a
value. [This is a useful bit of shell lore]

From: harvard!caip!princeton!allegra!ulysses!dgk (David Korn)

Just use the || operator

command || failure_command
[Also suggested by Robert C. Chancer <homxb!rcc>]

>From caip!clyde!cbatt!cbdkc1!cbnap!whp
How 'bout:

	ls mojo
	if [ ! $? ]
	then	echo foo
	else	echo bar
	fi

>From: harvard!violet!seismo!ucb-vax.ARPA!jason

Try combinations for test ([) and expr.

From topaz!pegasus!hansen
csh:
    ls foo
    if (! $status) then
       echo "foo exists"
    endif

sh:
    ls foo
    if [ $? != 0 ]; then
       echo "foo exists"
    endif

If you have the System Vr2 (or later) sh (also available on SUN 3.0) or the
ksh, then you can do the following:

	not() { if eval "$@"; then return 1; else return 0; fi; }

and use it exactly as you indicated:

    if not ls foo
    then
	    echo foo does not exist
    fi

					Tony Hansen
					ihnp4!pegasus!hansen


I think Tony Hansen's answer is the most useful for me. Using his Bourne
shell not function I can arbitrarily not the return status of any command
in a concise way. This is important because it is SO easy to write
non-readable shell scripts.  Thank you all!
-- 
"Life is but a dream" - Lope de Vega
    "...for some and a NIGHTMARE for others!" Merlin, "Excalibur", the movie
Disclaimer?  What disclaimer?  I can back everything up with as much 
drivel as you like!

anw@nott-cs.UUCP (08/20/86)

In article <6228@sun.uucp> guy@sun.uucp (Guy Harris) writes:
>Try
>
>	if ls foo
>	then
>		:
>	else
>		echo foo does not exist
>	fi

Or you could try

	ls foo ||
	    echo foo does not exist

In complicated situations, "if ... then ... else ... fi" is clearer, but
where there is only one subsidiary command I think "&&" and "||" can tidy
up shell scripts quite a lot.  I often use (V7 with SV shell) something like

	[ -w foo ] || fault "can't write to foo"

where "fault" is a suitable function, such as

	fault () { echo $0: error, "$@" 1>&2; exit 1; }

						-- Andy Walker,
						     Maths Dept, Nottm Univ

ignatz@aicchi.UUCP (Ihnat) (08/22/86)

There may be more elegant ways--it's sometimes tough to be elegant at 2:50
AM--but certainly, for filename FILE

	ls FILE >/dev/null 2>/dev/null

	if [ ! $? ]
	then
		<whatever negated thingies you want>
	fi;

works.  (As we all know, $? is the return code from the last executed command.)
However, if just testing existence, how about

	if [ -f FILE ]
	then
		<etc>
	fi;

Look at test(1); it's got a lot of nifty cases you can test...
-- 
	Dave Ihnat
	Analysts International Corporation
	(312) 882-4673
	ihnp4!aicchi!ignatz || ihnp4!homebru!ignatz

sja@ih1ap.UUCP (Steve Alesch) (09/12/86)

In article <6228@sun.uucp>, guy@sun.uucp (Guy Harris) writes:
> > The  key  thing  here  is  the  ability  to NOT the value of status. How is
> > this similar thing done in Bourne shell.
> > 
> > if ! ls foo
> > then
> > 	echo foo does not exist
> > fi
> 
> Try
> 
> 	if ls foo
> 	then
> 		:
> 	else
> 		echo foo does not exist
> 	fi
> 
> The ":"  is the pseudo-comment from old Bourne shells; it's really a command
> that does nothing.
> 
> Not the cleanest syntax, but that's life.  (However, I'd rather have a shell
> that requires that crud, but allows you to redirect the output of a "for"
> loop, than one that permits you to negate exit status directly but won't let
> you redirect the output of loops!  At least with the Bourne shell you can
> get around the inability to negate exit status fairly easily.)
> 
> However, you may be better off doing
> 
> 	if test ! -f foo
> 
> or something like that; unfortunately, "test" doesn't have a predicate for
> "just test whether it exists", but you may really want a more restrictive
> predicate anyway.

Correct me if I'm missing something.  What's wrong with:

	ls foo
	if [ $? != 0 ]; then
		echo foo does not exist
	fi
-- 

Steve Alesch	AT&T
(312)510-7881, ...!ihnp4!ih1ap!sja

chris@pixutl.UUCP (chris) (09/16/86)

> 
> Correct me if I'm missing something.  What's wrong with:
> 
> 	ls foo
> 	if [ $? != 0 ]; then
> 		echo foo does not exist
> 	fi
> -- 
> 
> Steve Alesch	AT&T
> (312)510-7881, ...!ihnp4!ih1ap!sja


It should be:

	if [ $? -ne 0 ]; then

  '!=' is used to compare strings, -ne and family, integers...  :-)


  Chris
-- 

 Chris Bertin       :  (603) 881-8791 x218
 xePIX Inc.         :
 51 Lake St         :  {allegra|ihnp4|cbosgd|ima|genrad|amd|harvard}\
 Nashua, NH 03060   :     !wjh12!pixel!pixutl!chris

dianeh@ism780c.UUCP (Diane Holt) (09/17/86)

In article <574@ih1ap.UUCP> sja@ih1ap.UUCP (Steve Alesch) writes:
>In article <6228@sun.uucp>, guy@sun.uucp (Guy Harris) writes:
>> > The  key  thing  here  is  the  ability  to NOT the value of status.
>> > How is this similar thing done in Bourne shell.
>> > if ! ls foo
>> > then
>> > 	echo foo does not exist
>> > fi
>> 
>> Try
>> 	if ls foo
>> 	then
>> 		:
>> 	else
>> 		echo foo does not exist
>> 	fi
>> [or]
>> 	if test ! -f foo
>> 
>Correct me if I'm missing something.  What's wrong with:
>	ls foo
>	if [ $? != 0 ]; then
>		echo foo does not exist
>	fi

I didn't see the original posting, so I'm not sure exactly what's trying to
be done, but my suggestion would be:

	ls foo || echo "foo does not exist"

The || is "OR" -- return "true" from the first command "OR" execute the
next one. Double ampersand (&&) is used to check the return from the first
command "AND" execute the next one. There is no limit on how many "next"
commands there can be or any restrictions on combinations of "OR"s and
"AND"s. I use this all the time.

P.S.
Obviously, this whole example is pretty silly, since 'ls' will output
"foo not found", if it doesn't really exist, so echoing that it doesn't is
superfluous...but I'm assuming that the command used is just an example and
not significant to the original poster's question...if it really *is*
significant, then you'd want to redirect the output: ls foo >/dev/null 2>&1...

Diane Holt
Interactive Systems Corp.
Santa Monica, CA
{seismo,decvax,cbosgd}!hplabs!sdcrdcf!ism780c!dianeh

"But I don't know anything about computers."
"Nobody does...but don't you want one for when you do find out?"

guy@sun.uucp (Guy Harris) (09/17/86)

> Correct me if I'm missing something.  What's wrong with:
> 
> 	ls foo
> 	if [ $? != 0 ]; then
> 		echo foo does not exist
> 	fi

It doesn't indicate quite as clearly as the other version that the
failure/success of "ls" is being tested.  It merely indicates that the exit
status of "ls" is being compared against 0; you have to associate this with
failure/success.  (See past discussions in net.lang.c about why Boolean
types exist even if you language happens to implement them as integral
types.)

In addition, 1) "ls" does not always return an exit status indicating
whether it could find the files in question or not and 2) "ls" *does* always
print the name of the file, if it finds it, or an error, if it doesn't.  If
"test" had a "does this file exist" predicate, then as I mentioned that
would be what you should use.
-- 
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com (or guy@sun.arpa)

lilly@leadsv.UUCP (Harriette Lilly) (09/27/86)

        Speaking of C shells.....

        I am just getting into some deep shell programming and have exausted
        (I think ) the resources here....

        I would like to find someone (or more than one) that I could
        exchange E-mail with about shells and possibly get some answers
        to some problems I am having.


        Any help in this area would be greatly appreciated.

        Thanx in advance....
						Harriette
						@ Lockheed for
						Telos Consulting

lilly@leadsv.UUCP (Harriette Lilly) (09/29/86)

           Thanks to those who answered, I will be writting you soon
           as if figure out how :-)

           P.S. I already have the UNIX C SHELL Field Guide, But even it
                it not answering all my questions.