The Answer Guy 54: "Unary Command Expected" in Shell Script
"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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
![[ Index of Past Answers ]](../../gx/dennis/answerpast.jpg)