[ Prev ] [ Table of Contents ] [ Front Page ] [ FAQ ] [ Next ]


(?) The Answer Guy (!)


By James T. Dennis, [email protected]
LinuxCare, http://www.linuxcare.com/


(?) "Unary Command Expected" in Shell Script

From J.Keo Power on Fri, 05 May 2000

Hi Jim,

My name is Keo. I have been trying to write a script that provides a salutation to the user, though that is different depending on who logs in. There are only three of us logging in on the system, and I want to have a little fun with them by putting in some cool messages.

So far, I have attempted to write a script in vi named intro and placing the file in my home directory. I have "chmod to ugo+x intro". Then going to the /etc/bashrc file and putting in the path of the executable intro file in my home directory.

The bashrc is trying to run the executable, but is returning the message "unary command expected". I am not sure what that means!

If you could give me a little guidance on if my methodology is correct as far as the files I am manipulating, and possibly an outline of the script to write. here is what I have attempted (last time):

 #! intro
 # test of login script

 name=$LOGIN
 if [ $name = keo ]
 then
     echo "Whats up mano?"
 else
     if [ $name = dan ]
     then
         echo "Lifes a peach, homeboy."
     else
          if [ $name = $other ]
             then
                 exit
          fi
     fi
 fi
 exit

Thanks for any help. Keo

(!) I've been trying to clean out my inbox of the 500 messages that have been sitting unanswer and unsorted for months.
This is one of them that I just couldn't pass up.
First problem with this script is right at the first line. That should be a "she-bang" line --- like:
#!/bin/sh
... which is normally found at the beginning of all scripts.
The "she-bang" line is sometimes called "hash bang" -- so-called because the "#" is called a "hash" in some parts, and the "!" is often called a "bang" among hackers, it's also short for "shell-bang" according to some. It looks like a comment line --- but it is used by the system to determine where to find an interpreter that can handle the text of any script. Thus you might see 'awk' programs start with a line like:
#!/usr/bin/gawk -f
... or PERL programs with a she-bang like:
#!/usr/local/bin/perl
... and programs written using the 'expect' language (a derivative of TCL) would naturally start with something like:
#!/usr/local/bin/expect -f
After you fix that here are some other comments that I've inserted into your code (my comments start with the ## -- double hash):
 #! intro
 # test of login script

 name=$LOGIN
##  should be quoted:  name="$LOGIN" in case $LOGIN had
## any embedded whitespace.  It shouldn't, but your scripts
## will be more robust if you code them to accept the most
## likely forms of bad input.

## Also I don't think $LOGIN is defined on most forms of
## UNIX.  I know of $LOGNAME and $USER, but no $LOGIN

## Finally, why assign this to some local shell variable?
## Why not just use the environment variable directly
## since you're not modifying it?

 if [ $name = keo ]
 then
     echo "Whats up mano?"
## That can be replaced with:
##     [ "$name" = "keo" ] && echo "What's up mano?"
## Note the quotations, and the use of the && conditional
## execution operator
 else
## don't need an else, just let this test drop through to here
## (the else would be useful for cases where the tests were expensive
## or they had "side effects."
     if [ $name = dan ]
     then
         echo "Lifes a peach, homeboy."
## [ "$name" = "dan" ] && echo "Lifes a peach, homeboy."
     else
          if [ $name = $other ]
             then
                 exit
          fi
     fi
 fi
 exit
## $other is undefined.  Thus the [ ('test') here will give
## you a complaint.  If it was written as: [ "$name" = "$other" ]
## then the null expansion of the $other (undefined) variable
## would not be a problem for the 'test' command.  The argument
## would be there, albeit empty.  Otherwise the = operation
## to the 'test' command will not have its requisite TWO operands.

## All eight of these trailing lines are useless.  You can just
## drop out of the nested tests with just the two 'fi' delimiters
## (technically 'fi' is not a command, it's a delimiter).
Here's a more effective version of the script:
#!/bin/sh
case "$LOGNAME" in
     jon)
	echo "Whats up mano?" ;;
     dan)
	echo "Lifes a peach, homeboy."
       *)
       # Do whatever here for any other cases
       ;;
esac
This is pretty flexible. You can easily extend it for additional cases by insering new "foo)" clauses with their own ";;" terminators. It also allows you to use shell globbing and some other pattern matching like:
#!/bin/sh
case "$LOGNAME" in
     jon|mary)
	echo "Whats up mano?" ;;
     dan)
	echo "Lifes a peach, homeboy."
     b*)
	echo "You bad, man!"
       ;;
esac
Note that this sees "Jon" or "Mary" in the first clause, Dan in the second and anyone whose login name starts with a "b" in the last case.
Any good book on shell scripting will help you with this.


Copyright © 2000, James T. Dennis
Published in The Linux Gazette Issue 54 June 2000
HTML transformation by Heather Stern of Tuxtops, Inc., http://www.tuxtops.com/


[ Answer Guy Current Index ] greetings   1   2   3   4   5   6   7   8   9   10   11   12   13   14   15   16   17   18 [ Index of Past Answers ]


[ Prev ] [ Table of Contents ] [ Front Page ] [ FAQ ] [ Next ]