Thread View: comp.sys.apple2.gno
4 messages
4 total messages
Started by Doug Lenz
Tue, 29 Dec 1992 15:04
Why shouldn't you use csh?
Author: Doug Lenz
Date: Tue, 29 Dec 1992 15:04
Date: Tue, 29 Dec 1992 15:04
449 lines
12496 bytes
12496 bytes
Hi everyone!
After following the discussion about csh vs. any other REAL shell, I thought
I'd include the "Why you shouldn't use csh FAQ"...
(PS: Another thing to try, find a Sun workstation and do a man on csh. The
man page TELLS you you shouldn't actually try to use csh for writing
scripts... What's the point?)
Here it is:
===========
From: Tom Christiansen <tchrist@pixel.Convex.COM>
Date: Mon, 2 Nov 1992 22:14:18 GMT
Newsgroups: comp.unix.shell,comp.unix.questions,news.answers
Subject: Csh Programming Considered Harmful
Archive-name: unix-faq/shell/csh-whynot
Version: $Id: csh-faq,v 1.1 92/11/02 15:12:23 tchrist Exp Locker: tchrist $
The following periodic article answers in excruciating detail
the frequently asked question "Why shouldn't I program in csh?".
It is available for anon FTP from convex.com in /pub/csh.whynot .
Csh Programming Considered Harmful
Resolved: The csh is a tool utterly inadequate for programming, and
its use for such purposes should be strictly banned.
I am continually shocked and dismayed to see people write test cases,
install scripts, and other random hackery using the csh. Lack of
proficiency in the Bourne shell has been known to cause errors in /etc/rc
and .cronrc files, which is a problem, because you *must* write these files
in that language.
The csh is seductive because the conditionals are more C-like, so the path
of least resistance if chosen and a csh script is written. Sadly, this is
a lost cause, and the programmer seldom even realizes it, even when they
find that many simple things they wish to do range from cumbersome to
impossible in the csh.
FILE DESCRIPTORS
The most common problem encountered in csh programming is that
you can't do file-descriptor manipulation. All you are able to
do is redirect stdin, or stdout, or dup stderr into stdout.
Bourne-compatible shells offer you an abundance of more exotic
possibilities.
Writing Files
In the Bourne shell, you can open or dup random file descriptors.
For example,
exec 2>errs.out
means that from then on, stderr goes into errs file.
Or what if you just want to throw away stderr and leave stdout
alone? Pretty simple operation, eh?
cmd 2>/dev/null
Works in the Bourne shell. In the csh, you can only make a pitiful
attempt like this:
(cmd > /dev/tty) >& /dev/null
But who said that stdout was my tty? So it's wrong. This simple
operation \fIcannot be done\fP in the csh.
Along these same lines, you can't direct error messages in csh
scripts out stderr as is considered proper. In Bourne shell, you
might say:
echo "$0: cannot find $file" 1>&2
but in the csh, you can't redirect stdout out stderr, so you end
up doing something silly like this:
sh -c 'echo "$0: cannot find $file" 1>&2'
Reading Files
In the csh, all you've got is $<, which reads a line from your tty. What
if you've redirected stdin? Tough noogies, you still get your tty, which
you really can't redirect. Now, the read statement
in the Bourne shell allows you to read from stdin, which catches
redirection. It also means that you can do things like this:
exec 3<file1
exec 4<file2
Now you can read from fd 3 and get lines from file1, or from file2 through
fd 4. In modern, Bourne-like shells, this suffices:
read some_var 0<&3
read another_var 0<&4
Although in older ones where read only goes from 0, you trick it:
exec 5<&0 # save old stdin
exec 0<&3; read some_var
exec 0<&4; read another_var
exec 0<&5 # restore it
Closing FDs
In the Bourne shell, you can close file descriptors you don't
want open, like 2>&-, which isn't the same as redirecting it
to /dev/null.
More Elaborate Combinations
Maybe you want to pipe stderr to a command and leave stdout alone.
Not too hard an idea, right? You can't do this in the csh as I
mentioned in 1a. In a Bourne shell, you can do things like this:
exec 3>&1; grep yyy xxx 2>&1 1>&3 3>&- | sed s/file/foobar/ 1>&2 3>&-
grep: xxx: No such foobar or directory
Normal output would be unaffected. The closes there were in case
something really cared about all its FDs. We send stderr to sed,
and then put it back out 2.
Consider the pipeline:
A | B | C
You want to know the status of C, well, that's easy: it's in $?, or
$status in csh. But if you want it from A, you're out of luck -- if
you're in the csh, that is. In the Bourne shell, you can get it, although
doing so is a bit tricky. Here's something I had to do where I ran dd's
stderr into a grep -v pipe to get rid of the records in/out noise, but had
to return the dd's exit status, not the grep's:
device=/dev/rmt8
dd_noise='^[0-9]+\+[0-9]+ records (in|out)$'
exec 3>&1
status=`((dd if=$device ibs=64k 2>&1 1>&3 3>&- 4>&-; echo $? >&4) |
egrep -v "$dd_noise" 1>&2 3>&- 4>&-) 4>&1`
exit $status;
COMMAND ORTHOGONALITY
Built-ins
The csh is a horrid botch with its built-ins. You can't put them
together in many reasonable way. Even simple little things like this:
% time | echo
which while nonsensical, shouldn't give me this message:
Reset tty pgrp from 9341 to 26678
Others are more fun:
% sleep 1 | while
while: Too few arguments.
[5] 9402
% jobs
[5] 9402 Done sleep |
Some can even hang your shell. Try typing ^Z while you're sourcing
something, or redirecting a source command. Just make sure you have
another window handy.
Flow control
You can't mix flow-control and commands, like this:
who | while read line; do
echo "gotta $line"
done
You can't combine multiline constructs in a csh using semicolons.
There's no easy way to do this
alias cmd 'if (foo) then bar; else snark; endif'
Stupid parsing bugs
Certain reasonable things just don't work, like this:
% kill -1 `cat foo`
`cat foo`: Ambiguous.
But this is ok:
% /bin/kill -1 `cat foo`
If you have a stopped job:
[2] Stopped rlogin globhost
You should be able to kill it with
% kill %?glob
kill: No match
but
% fg %?glob
works.
White space can matter:
if(expr)
may fail on some versions of csh, while
if (expr)
works!
SIGNALS
In the csh, all you can do with signals is trap SIGINT. In the Bourne
shell, you can trap any signal, or the end-of-program exit. For example,
to blow away a tempfile on any of a variety of signals:
$ trap 'rm -f /usr/adm/tmp/i$$ ;
echo "ERROR: abnormal exit";
exit' 1 2 3 15
$ trap 'rm tmp.$$' 0 # on program exit
6. QUOTING
You can't quote things reasonably in the csh:
set foo = "Bill asked, \"How's tricks?\""
doesn't work. This makes it really hard to construct strings with
mixed quotes in them. In the Bourne shell, this works just fine.
In fact, so does this:
cd /mnt; /usr/ucb/finger -m -s `ls \`u\``
Dollar signs cannot be escaped in double quotes in the csh. Ug.
set foo = "this is a \$dollar quoted and this is $HOME not quoted"
dollar: Undefined variable.
You have to use backslashes for newlines, and it's just darn hard to
get them into strings sometimes.
set foo = "this \
and that";
echo $foo
this and that
echo "$foo"
Unmatched ".
Say what? You don't have these problems in the Bourne shell, where it's
just fine to write things like this:
echo 'This is
some text that contains
several newlines.'
VARIABLE SYNTAX
There's this big difference between global (environment) and local
(shell) variables. In csh, you use a totally different syntax
to set one from the other.
In Bourne shell, this
VAR=foo cmds args
is the same as
(export VAR; VAR=foo; cmd args)
or csh's
(setenv VAR; cmd args)
You can't use :t, :h, etc on envariables. Watch:
echo Try testing with $SHELL:t
It's really nice to be able to say
${PAGER-more}
or
FOO=${BAR:-${BAZ}}
to be able to run the user's PAGER if set, and more otherwise.
You can't do this in the csh. It takes more verbiage.
You can't get the process number of the last background command from the
csh, something you might like to do if you're starting up several jobs in
the background. In the Bourne shell, the pid of the last command put in
the background is available in $!.
The csh is also flaky about what it does when it imports an
environment variable into a local shell variable, as it does
with HOME, USER, PATH, and TERM. Consider this:
% setenv TERM '`/bin/ls -l / > /dev/tty`'
% csh -f
And watch the fun!
EXPRESSION EVALUATION
Consider this statement in the csh:
if ($?MANPAGER) setenv PAGER $MANPAGER
Despite your attempts to only set PAGER when you want
to, the csh aborts:
MANPAGER: Undefined variable.
That's because it parses the whole line anyway AND EVALUATES IT!
You have to write this:
if ($?MANPAGER) then
setenv PAGER $MANPAGER
endif
That's the same problem you have here:
if ($?X && $X == 'foo') echo ok
X: Undefined variable
This forces you to write a couple nested if statements. This is highly
undesirable
because it renders short-circuit booleans useless in situations like
these. If the csh were the really C-like, you would expect to be able
to safely employ this kind of logic. Consider the common C construct:
if (p && p->member)
Undefined variables are not fatal errors in the Bourne shell, so
this issue does not arise there.
While the csh does have built-in expression handling, it's not
what you might think. In fact, it's space sensitive. This is an
error
@ a = 4/2
but this is ok
@ a = 4 / 2
ERROR HANDLING
Wouldn't it be nice to know you had an error in your script before
you ran it? That's what the -n flag is for: just check the syntax.
This is especially good to make sure seldom taken segments of code
code are correct. Alas, the csh implementation of this doesn't work.
Consider this statement:
exit (i)
Of course, they really meant
exit (1)
or just
exit 1
Either shell will complain about this. But if you hide this in an if
clause, like so:
#!/bin/csh -fn
if (1) then
exit (i)
endif
The csh tells you there's nothing wrong with this script. The equivalent
construct in the Bourne shell, on the other hand, tells you this:
#!/bin/sh -n
if (1) then
exit (i)
endif
/tmp/x: syntax error at line 3: `(' unexpected
RANDOM BUGS
Here's one:
fg %?string
^Z
kill %?string
No match.
Huh? Here's another
!%s%x%s
Coredump, or garbage.
If you have an alias with backquotes, and use that in backquotes in
another one, you get a coredump.
Try this:
% repeat 3 echo "/vmu*"
/vmu*
/vmunix
/vmunix
What???
While some vendors have fixed some of the csh's bugs (the tcsh also
does much better here), most of its problems can never be solved
because they're a result of braindead design decisions. Do yourself
a favor, and if you have to write a shell script, do it in the
Bourne shell.
--
Tom Christiansen tchrist@convex.com convex!tchrist
If you have ever seen the grim word "login:" on a screen, your mind
is now a wholly-owned subsidiary of The Death Star.
John Woods in <14105@ksr.com> of comp.unix.bsd
--
=============================================================
| Douglas Lenz | Friends don't let friends use MS-DOS |
-------------------------------------------------------------
| internet : lenz@ssd.comm.mot.com |
=============================================================
Re: Why shouldn't you use csh?
Author: Jawaid Bazyar
Date: Wed, 30 Dec 1992 08:19
Date: Wed, 30 Dec 1992 08:19
16 lines
1202 bytes
1202 bytes
lenz@ssd.comm.mot.com (Doug Lenz) writes: >Hi everyone! >After following the discussion about csh vs. any other REAL shell, I thought >I'd include the "Why you shouldn't use csh FAQ"... >(PS: Another thing to try, find a Sun workstation and do a man on csh. The > man page TELLS you you shouldn't actually try to use csh for writing > scripts... What's the point?) Where? Could you quote the relevant text? The csh manpage is _large_ :) -- Jawaid Bazyar | Ask me about the GNO Multitasking Environment Procyon, Inc. | for the Apple IIgs! bazyar@cs.uiuc.edu | P.O Box 620334 --Apple II Forever!-- | Littleton, CO 80162-0334 (303) 933-4649
Re: Why shouldn't you use csh?
Author: Howard Huang
Date: Wed, 30 Dec 1992 16:38
Date: Wed, 30 Dec 1992 16:38
23 lines
1517 bytes
1517 bytes
bazyar@teal.csn.org (Jawaid Bazyar) writes:
>(PS: Another thing to try, find a Sun workstation and do a man on csh. The
> man page TELLS you you shouldn't actually try to use csh for writing
> scripts... What's the point?)
Where? Could you quote the relevant text? The csh manpage is _large_ :)
The last paragraph of my manpage doesn't quite say that, but does say:
Although robust enough for general use, adventures into the
esoteric periphery of the C shell may reveal unexpected
quirks.
Hm.
------------------------------------------------------------------------------
Howard C. Huang * The MITRE Corporation * hhuang@mitre.org
I have yet to meet the man who is as fond
of virtue as he is of beauty in women.
------------------------------------------------------------------------------
Re: Why shouldn't you use csh?
Author: Doug Lenz
Date: Wed, 30 Dec 1992 19:08
Date: Wed, 30 Dec 1992 19:08
15 lines
1133 bytes
1133 bytes
That's easy, look in the extremely LONG BUGS section... may I quote "Although robust enough for general use, adventures into the esoteric periphery of the C shell may reveal unexpected quirks" This is updated from the warning in the old Sun 3 man pages where they pretty much said "Don't use this for shell programming !" Doug -- ============================================================= | Douglas Lenz | Friends don't let friends use MS-DOS | ------------------------------------------------------------- | internet : lenz@ssd.comm.mot.com | =============================================================
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads