Personally, I prefer perl and sh/bash.
I append here an HTML-ized version of a posting from 1991 by Tom Christiansen (who, at that time, was tchrist@convex.com-- I don't know if this is still a valid address), on why one should not program in csh.
>From the keyboard of apl@world.std.com (Anthony P Lawrence):
:So, the question is: why is the csh so inappropriate for shell
:programming and why don't those using it realize this?
I've been trying to hold back my "don't do programming in csh"
warnings to one a day, but since you asked, let me attempt to
spell out some good reasons. I preface this from the tail of the
csh man page on Suns.
Although robust enough for general use, adventures
into the esoteric periphery of the C shell may reveal
unexpected quirks.
So here's a bunch of reasons why not to use the csh for programming.
I suspect that after reading them you'll agree.
--tom
exec 2>errs.outmeans that from then on, all of stderr goes into errs file. Or what if you just want to throw away stderr and leave stdout alone?
cmd 2>/dev/nullWorks in the Bourne shell. In the csh, you can only make a pitiful attempt like this:
(cmd > /dev/tty) >& /dev/nullBut who said that stdout was my tty? So it's wrong.
exec 3<file1 exec 4<file2Now you can read from fd 3 and get lines from file1, or from file2 through fd 4. In modern bournelike shells, this suffices:
read some_var 0<&3 read another_var 0<&4Although 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
2>&-which isn't the same as redirecting it to /dev/null
exec 3>&1; grep yyy xxx 2>&1 1>&3 3>&- | sed s/file/foobar/ 1>&2 3>&- grep: xxx: No such foobar or directoryNormal output would be unaffected. The closes there were in case something really cared about all it's FDs. We send stderr to the sed, and then put it back out 2. Consider the pipeline:
A | B | CYou 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. In the Bourne shell, you can get it. 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;
% time | echowhich while nonsensical, shouldn't give me this message:
Reset tty pgrp from 9341 to 26678Others 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.
who | while read line; do echo "gotta $line" doneYou can't combine multiline things in a csh using semicolons. There's no easy way to do this
alias cmd 'if (foo) then bar; else snark; endif'
kill -1 `cat foo` `cat foo`: Ambiguous.But this is ok:
/bin/kill -1 `cat foo`
trap 'rm -f /usr/adm/tmp/i$$ ; echo "ERROR: abnormal exit"; exit' 1 2 3 15 trap 'rm tmp.$$' 0 # on program exit
set foo = 'isn\'t this so?'doesn't work. This makes it really hard to construct strings with mixed quotes in them. Dollar signs cannot be escaped in doublequotes 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??? echo $foo:qYou don't have these problems in the Bourne shell.
VAR=foo cmds argsis 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:tIt's really nice to be able to say
${PAGER-more}
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 verbage.
You can't get the process number of the last background
command from the csh. In the Bourne shell, it's $!.
fg %?string ^Z kill %?string No match.Huh? Here's another
!%s%x%sCoredump, 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 /vmunixWhat??? There are a lot, probably over 100, of these.