An extensive comparison of 'sh' and 'csh' language features

An extensive comparison of 'sh' and 'csh' language features

Post by Ken Manheim » Sat, 23 Nov 1991 00:05:57

Below is a presentation which i put together about particularly
consequential functional differences between the 'sh' and the 'csh'
shell command languages.  I've seen many assertions, in Unix
introductory books, in news postings, etc., about how sh is better for
scripting, or csh is better for interactions (and sometimes vice-
versa), but i don't think i've ever seen a direct comparison.  I'm
posting a start on such a beast in case anyone else might find it
useful, and also because i'm interested in filling in gaps - hearing
from others about important differences in functionality between the
two shell languages that i've missed (or gotten wrong).

The details are taken from the slides i made for an informal
presentation which i gave (at our CULB - Computer Users Lunch Bunch)
recently at work.  The presentation came out of notes that i
accumulated while idly thinking back (a late at night kind of thing,
and in fact, when i actually wound up generating the notes) to my own
experiences switching from csh- to sh-based shells both for scripting
and for my interactive login shell.

There is a preamble before the comparison which presents some of the
rationale i went through for even considering investing the energy to
scope out a whole new shell.  Before looking at 'sh' i was very
steeped in 'csh' - i do system and user support, and so answer lots of
shell interaction and script questions, and have implemented a few
very substantial scripts in csh.  (Some of you may be familiar with
'8mmbackup', a script that i wrote which a number of people around the
net have been using.  I've also done a few other utilities in 'csh',
and now some big ones in 'sh'.)  The combination of an interactive
shell with formidible interaction conveniences, like GNU-emacs-like
command-line interaction conveniences and so forth, builtin shell
functions, and greater prospects for POSIX compatibility, finally
prompted me to take a serious look, at least, at making the switch to
a 'sh'-based shell.

I can't be more emphatic that scripting in 'sh' is more manageable
than in 'csh', almost without regard to what you're doing, and the
benefits only increase as your job scales up.  The point of my
presentation, however, is that 'sh' language strengths are not only of
benefit for scripting - given the addition of user conveniences like
history, tilde notation, command line editing, and so forth, i find
that 'sh' makes a much better interactive command language substrate.
Hopefully this presentation begins to indicate some of the reasons for

Ken Manheimer                           Nat'l Inst of Standards and Technology (301)975-3539             (Formerly Nat'l Bureau of Standards)
      Factory Automation Systems Division Unix Systems Support Manager

                                        I like time.  It's one of my favorites.

                       A Comparison of Primary

                             UNIX SHELLS

                   Ken Manheimer (

            National Institute of Standards and Technology

                        WHAT ARE UNIX SHELLS?

 - Containers for delivery of explosive charges? Houses for mollusks?

The ones i'm talking about are a sort of container, but in a more
abstract way...

 - Unix shells are command interfaces for using computer software.

 - In the most rudimentary sense, each command shell, in general,
   provides an interactive base from which to successively `launch'

 - Any but the most minimal shell (CPM?) provides means for connecting
   things together:

    Environment - an operating context with state, which you can use
    to adjust/tailor your command interpreter in a systematic way - eg
    env vars, command history, command substitution, ...

    Glue - mechanisms for connecting together separate application
    operations in more than just sequence.

 - Differences get complex at this point.

                     WHAT ARE THE CHOICES ABOUT?

In UNIX, the glue is particularly important. UNIX' adheres to a policy
of promoting pervasive interconnectivity between applications.

 - This endows the potential both for powerful benefits in command

 - ... As well as requiring accommodation for the implicit tendency
   towards limiting of the power of individual commands.

Sophistication in command shells allowed their effective use beyond
immediate user interaction, as script programs for engaging
applications, in addition to interactive employment.

Divergence of two shells primary shells, csh and sh, stress different
strengths. The choices would be relatively easy if that's all there
was. But it isn't.

                          IN SIMPLER DAYS...

There was a time, after the beginning but before today, when the
choices were limited to `sh' (particularly the enhanced versions of
bourne shell) and `csh', and their relative strengths are fairly
clearcut (about which, more detail further below).

Sh is a worse interaction language -

   lacks job control
   lacks command history (indispensible if only for `!!')
   lacks tilde abbreviation ("~klm/.cshrc")

Csh is a worse programming language -

   lacks scoped functions
   lacks fine granularity file IO
   often less robust syntax and semantics

(It may even be reasonable to say that, for the times, and combined
with the peculiar compositional strengths of UNIX utilities, the
shells were relatively good at what they were supposed to do.)

                             A WRINKLE...

Due to `csh' distinct and substantial interaction conveniences, and
despite `sh' programming-language advantages, it has been fairly easy
to choose csh (or some enhanced csh) for your command interaction

But now, suppose that you could have all the interaction benefits of
csh, as well as prevalent refinements, etc, but built on top of either
csh or sh.

** Would the programming benefits of `sh' be of great enough benefit
   for the sake of interactive use to warrant the effort of learning a
   different command language for use as your login shell?

In fact, two of the most prevalent contemporary alternative shells,
csh-oriented `tcsh' and sh-oriented `bash', are similar enough in pure
interaction refinements that you would have to consider just this
question to decide between them. I think it's worth considering.

                            THE COMPARISON

Shell (bourne, csh) comparison


   - history
     - sh: no
     - csh: yes
   - tilde notation
     - sh: no
     - csh: yes
   - job control
     - sh: no
     - csh: yes
   - invocation shorthand and overload
     - See routines, below.
       - sh: sh functions - kinda powerful
       - csh: aliases - way feeble (but cute)
   - excluding merits of sh functions (below),
     csh slaughters sh for interaction conveniences.


 - sh: scoped functions
  - somewhat scalable - can recurse
  - no direct, persistent nested state
   - ie, routine 'packages' (modules)
     only by virtue of sub-shells.
 - csh: alias and labeled goto
  - goto - unstructured - no scoping
  - alias - textual substitution
   - single cmd or *brief* sequence
   - also no scoping
   - unruly - no syntactic integrity
    - bad partitioning between routine
      interior and invocation -
      outrageously awkward quoting
    - can encode syntactic fragments,
            eg 'if' part o'if/then/else/endif
      - has some "benefits", eg 'ifHostIn'
        set hostname=`/bin/hostname`
        alias ifHostIn echo "\!* | grep -s $hostname;" 'if ($status == 0) then'
        alias ifHostNotIn echo "\!* |grep -s $hostname;" 'if ($status==1) then'

        # Obtain accurate date from internet date
        # server if you're durer, or from durer
        # if you're not durer.
        ifHostNotIn durer
          rdate durer > /dev/null
          echo -n " rdate"
          # is a reliable authority:
          rdate $rdateMaster
          echo -n " rdate($rdateMaster)"
        endif   ## ifHostNotIn durer ##

        # BUT YOU CANNOT:

        # ifHostIn durer goon lurch squire mogul
        #   <do some stuff you want to do on them all>
        #   ifHostNotIn durer
        #     <do some stuff you want to do on all but durer>
        #   endif
        # endif

        # Csh gets badly confused, misses an endif and considers
        # *everything* below as being within the condition.
 - comparison
  - csh routines don't scale up
   - no scoping
   - limited to brief compositions
  - sh routines do, moderately


   - input reads - sh more powerful
     - any input line by line: sh only
       - This is significant.
       - Eg can read and process pipeline
         output line-by-line in sh, not
         so in csh.  (Unless save the output
         in a file and do a separate pass
         through the entire file for each line!)
     - token parsing reads: sh only
     - token syntax manipulation: sh only
       - by adjusting IFS var value
       - see string data type stuff, above
   - redirection - sh more powerful
     - stderr to stdout: both
       - sh: cmd 2>&1
       - csh: cmd |& cat
       - csh: cmd >& /dev/tty
     - stdout to stderr: sh only
       - cmd 1>&2
     - persistent redirection: sh only
       - 4>&1 #register for resurrection
         1>& wherever   #redirect stdout
         cmd       #output to 'wherever'
         ...   #Output still to wherever
         1>&4  #resume registered stdout


   - string-oriented conditionals
     - sh: idioms using IFS for parsing.
       For example, a func that gets the
       final component of a Unix path:
          PathTail () {
            # Return final path (or token) component of $1
            wasIFS="$IFS"; IFS="/$IFS"              #Prepend '/' to IFS repertoire.
            for bucket in $1; do : ; done       # Loop with '/' as whitespace.
            IFS="$wasIFS"                     # resurrect preexisting IFS.
            echo $bucket; }
       While this is a trivial case, the
       mechanism is general, useful for
       many things...
     - csh: var tail/head/... for parsing
        - Slightly more convenient but more
          limited than corresponding sh idioms
     - Neither provides string dissection
       (ie, no "substring <string> 3 4")
        - (tho u could do it, using, eg, case,
           and bending over backwards)
     - In sum, csh does some stuff more
        conveniently but doesn't do near
        as much, nor near as coherently.
   - arrays
     - csh has array-style ref to tokens
       - feebly implemented but terse
     - sh uses iteration idioms
       - comprehensive but not terse


   - sh: on demand, settable, clearable
   - csh: unitary pre hashing, redoable
   - Probably not determined which is
     preferable for general case.


 - csh has history, tilde, and
   (somewhat dubious) syntax-fragment
   textual substitution, lacking in sh.
   All primarily instrumental in facilitating
   command interaction.

 - Sh has much more powerful routine
   and data composition features,
   redirection features, and string
   and token handling features.  These
   are essential programming features.

 - (As mentioned,) csh is better for
   interaction, and sh is better for programming.
   - csh does not scale up as programming language

 - some of sh programming advantages are *very*
   conducive for interaction.
   - Eg, can read and process pipeline
     output line-by-line in sh, *not* so
     (without heinous finagling) in csh.
   - Functions provide much more robust -
     powerful and well-behaved - command
     substitution mechanism, facilitating
     easy (on-the-fly) and deep environment
     customization advantages.

 - Given inclusion of contemporary interaction
   facilities, as in bash and even 'ksh', at
   least some people may find distinct advantage
   in switching over to a sh-based shell.

That's it.


1. Want bash '&' to behave like csh '&'

Is there some way to make the bourne-ish shells ("bash" in
particular) behave like the csh-ish shells with respect to
how they handle jobs backgrounded with a '&'?  Bourne shells
kill all their backgrounded children when the shell dies,
and C shells leave backgrounded jobs running when the shell
dies.  I already know about nohup, but that's not an elegant
solution for our needs.  I'd like to make it work with just '&'.

(Background for why we want this...)

I've got a group of users who are mildly familiar with Unix (can
use ls, cp, rm, mv, et all, but that's about it.)

They currently use tcsh as their default shell and I want to
switch them to bash because its better for scripting, and I
don't have time anymore to maintain two sets of default login
scripts for all our settings (bourne and csh versions).

Anyway, I have seen that most of the functionality of tcsh they
use is also there in bash, so it should be smooth except that they
tend to background jobs alot with '&' for X11 programs started
from an xterm.

2. IrDA patches for 2.5.X on the way...

3. 'sh' after 'chroot'

4. Sendmail 8.6.10 and stdlib.h??

5. Problem with 'while' loop in 'sh'

6. Firewall Toolkit and Netscape...

7. 'sh' script spawning Sun 'cmdtool' running program

8. 2.4.2-a6 + ac7 -- OOPS on Athlon during boot -- invalid operand: 0000 in process lsmod

9. 'csh -f file' reads .cshrc on startup--feature or bug?

10. I need the sh's equivalent of csh's :r

11. Q:sh:Setting env by reading other files - like csh 'source'

12. 'for/next' loops in sh/csh??

13. Why doesn't this work (sh) and what's the (t)csh version?