New Messages
Editor:
I noticed that the last five code lines of the weekdate
program were
not published in my article in the July/August magazine.
Here are
those lines, with the prior two for context.
# Set the exit status according to whether today is that day of the month
# If you'd rather output the day number, uncomment the next line and
# comment the test line.
#
echo $day
#test $day -eq `date '+%d'`
Larry Reznick
Rezolution Computer Consulting
9085 Burst Court
Sacramento, CA 95826
csusac.ecs.csus.edu!rezbook!reznick
sactoh0.sac.ca.us!rezbook!reznick
From: Greg A. Woods <web.apc.org!woods@uunet.uu.net>
To: saletter@rdpub.com
Editor
I had to laugh over the letter from Christopher Calabrese
to Larry
Reznick in the July/August 1993 issue of Sys Admin!
They're both "wrong"!
This is an excellent example of folks going out and
making a whole
lot of assumptions about how things should be, and how
to go about
something. Shell scripts aren't that hard to write,
and it should
be possible for anyone to learn most of the basic rules.
No, you might
never have time to master the subtleties of all the
tools, but the
basic (de facto) rules still apply, and should be followed.
First off, there is a valid reason for the construct
"if test
"X$1" = "X" ..." You must do
this exactly this
way if you wish to be portable to V7, 4.2BSD, etc. systems,
for the
following reasons:
- "test" is the only portable way to invoke
the test(1) command
or shell builtin.
- The leading "X" is to prevent parsing (by
test(1)) of any
values with leading dashes, such as '-r'.
Indeed "if [ -z "$1" ] ..." is prettier,
but it's
just not portable.
Second, you should never use the test(1) "="
operator to compare
numeric values! Use "-eq", "-ne"
and their friends.
Third, the usage message in Christopher's re-implementation
did not
follow any standard syntax I've ever run across! The
"..."
means the previous element may be repeated zero or more
times.
Fourth, usage errors are often indicated by an exit
code of two (2).
Fifth, the "#!" interpreter file magic "number"
should
be "#! ". The space is required by many 4.2BSD
implementations,
and is documented as so. This won't ensure that /bin/sh
runs the script
on some systems, such as older SCO Xenix machines where
the user's
shell is csh(1), and nor can any other portable solution,
other than
"rm /bin/csh"!
Oh, and in the first sed(1) expression, the dots don't
have to be
escaped with backslashes -- this is only necessary in
the RE portion
of a substitute expression.
As a final note, I consider the possible separate execution
of two
sed(1) processes to be a small price to pay for readability,
and for
the assurance of avoiding bugs due to filenames containing
whitespace.
Yes, such occurrences should be tracked down and eradicated,
but it's
the programmer's job to predict and avoid the consequences
of all
possible errors!
A better, different, but not much more portable, implementation,
derived
from Christopher's, is in Listing 1 (and yes, I tested
this code!).
Of course all of this is moot for most sh(1) or ksh(1)
users. They
can use the "type" builtin [or for ksh(1),
the "whence"
builtin, which is an alias for "whence -v"]
(except it doesn't
set an exit code, nor bore you with the path it searched
in, though
it can identify shell functions and for ksh(1), aliases).
The original
csh(1) version of which(1) also knows to check for aliases.
Note that
for sh(1) users, an implementation of which(1) using
"type"
would have to be a shell function, set in $HOME/.profile
or some such
place, since any shell script would be unable to search
for shell
functions itself.
BTW, the font used for examples makes it impossible
to distinguish
between a single quote (') and a single back-quote (`).
Greg A. Woods
Larry Reznick responds: I agree with you completely
that
the "X$1" test has its place, given the conditions
you outline.
My inclusion of it in the original script was a holdover
from when
I knew less. Now that I know more, including what you
point out, I
won't apologize for it any more.
On other points: I also agree that test is the most
portable
way to handle the program name, but the brackets just
seem more natural-looking
to me. Now that you bring it up, I do notice where Christopher
used
the "=" operator -- definitely a string operator
--
instead of the ".eq" operator. I missed that
when I looked
at his code. That sets up for strange troubles later.
About the usage error being 2: I've never seen that
documented
anywhere. The only documentation on the convention I've
seen is the
zero/non-zero convention. I'd be interested in knowing
where you found
such a standard. I usually adhere to local standards
where I'm doing
the work. Without such standards, I've used 1 for usage,
2 for file
opening, 3 for read/write (3 for read & 4 for write
when I need to
distinguish), and 4 for memory. I don't recall if I've
needed to go
beyond that. This corresponds with the usual sequence
of events in
the program with the possible exchange of read/write
& memory, according
to the program.
BSD may require the "#!" be followed by a
space.
I don't have access to a BSD machine any more to verify
that, so I
trust you. However, SVR4 doesn't require the space.
The documentation
in csh(1) says, "the next word," when referring
to what follows.
That can certainly be interpreted as requiring a space,
but I have
a great deal of evidence that the space isn't required
in SVR4: every
shell script using that notation to start sh(1) but
not having the
space wouldn't run under csh. Here are the rules for
naming the shell
in a shell script:
1. If the first line begins with #!, what follows is
the
name of a shell or command to interpret the script.
2. When option 1 fails, if the first character of the
first
line begins with a #, csh is invoked.
3. When option 2 fails, invoke sh. As a tradition, I've
seen a colon ':' used as the only character on the first
line to avoid
putting a # in the first position.
Based on these rules, the colon you write on the second
line of your code serves no code purpose except that
the shell interprets
the colon as a null command, which does nothing successfully.
Finally, the which script that I use (I forgot about
the
type builtin -- thanks for the reminder) does announce
aliases
in precedence over commands using the same names. At
the end of the
original article, I challenged readers to add that facility.
Thanks
for your contributions.
MM responds: We have a filter to catch the back-quote
problem
but had not used it with New Messages! We will now do
so.
From: Wolfgang Schrecker <cat.de!schreckr@uunet.uu.net>
Subject: ftp-site
Hi, sorry to bother you. But as a customer who doesn't
what to type
all your goodies, is there a FTP site to get the sources
& scripts?
Wolfgang Schrecker
Start Informatik GmbH
eMail: schreckr@cat.de
Compuserve:INTERNET>schreckr@cat.de
Look for the "Source Code Availability" reference
in the contents on the cover of Sys Admin. All code
listings are available
either using UUCP or ftp. --rlw
|