分享
 
 
 

sh与csh的比较

王朝other·作者佚名  2008-05-18
窄屏简体版  字體: |||超大  

无意中在网上找到了一份关于sh与csh比较的资料(实际上原文叫Why no csh.),不知道有没有在此贴过.但本人觉得so cool.不敢独享.如果贴过我就再贴一次吧.如果没有贴过那就最好.我也不用担心被人说抄袭.如果你想转载此文章,请保留原文的完整性.当然,我的屁话就不用转了.

原文:

From comp.unix.shell Thu Sep 28 16:13:17 1995

Path: night.primate.wisc.edu!nntp.msstate.edu!gatech!news.sprintlink.net!in1.uu.net!boulder!csnews!mox!tchrist

From: Tom Christiansen <tchrist@mox.perl.com>

Newsgroups: comp.unix.shell,comp.unix.questions,comp.unix.programmer,comp.answers,news.answers,comp.infosystems.www.authoring.cgi

Subject: Csh Programming Considered Harmful

Followup-To: comp.unix.shell

Date: 28 Sep 1995 18:52:45 GMT

Organization: scant

Lines: 560

Approved: news-answers-request@MIT.Edu

Expires: Fri, 1 Nov 1994 12:00:00 GMT

Message-ID: <44eqtt$h7j@csnews.cs.colorado.edu>

NNTP-Posting-Host: perl.com

Originator: tchrist@mox

Xref: night.primate.wisc.edu comp.unix.shell:8718 comp.unix.questions:16357 comp.unix.programmer:10254 comp.answers:5900 news.answers:20987 comp.infosystems.www.authoring.cgi:10967

Archive-name: unix-faq/shell/csh-whynot

Version: $Id: csh-faq,v 1.7 95/09/28 12:52:17 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 perl.com in /pub/perl/versus/csh-whynot.gz

*** 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 is 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.

1. 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.

1a. Writing Files

In the Bourne shell, you can open or dup arbitrary 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 *CANNOT BE DONE* in the csh.

Along these same lines, you can't direct error messages in csh scripts

out stderr as is considered proper. In the 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'

1b. 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

1c. 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.

1d. 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;

The csh has also been known to close all open file descriptors besides

the ones it knows about, making it unsuitable for applications that

intend to inherit open file descriptors.

2. COMMAND ORTHOGONALITY

2a. Built-ins

The csh is a horrid botch with its built-ins. You can't put them

together in many reasonable ways. 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. Or try

% history | more

on some systems.

Aliases are not evaluated everywhere you would like them do be:

% alias lu 'ls -u'

% lu

HISTORY News bin fortran lib lyrics misc tex

Mail TEX dehnung hpview logs mbox netlib

% repeat 3 lu

lu: Command not found.

lu: Command not found.

lu: Command not found.

% time lu

lu: Command not found.

2b. 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'

You can't perform redirections with if statements that are

evaluated solely for their exit status:

if ( { grep vt100 /etc/termcap > /dev/null } ) echo ok

And even pipes don't work:

if ( { grep vt100 /etc/termcap | sed 's/$/###' } ) echo ok

But these work just fine in the Bourne shell:

if grep vt100 /etc/termcap > /dev/null ; then echo ok; fi

if grep vt100 /etc/termcap | sed 's/$/###/' ; then echo ok; fi

Consider the following reasonable construct:

if ( { command1 | command2 } ) then

...

endif

The output of command1 won't go into the input of command2. You will get

the output of both commands on standard output. No error is raised. In

the Bourne shell or its clones, you would say

if command1 | command2 ; then

...

fi

2c. 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! Your vendor may have attempted to fix this bug, but odds are good

that their csh still won't be able to handle

if(0) then

if(1) then

echo A: got here

else

echo B: got here

endif

echo We should never execute this statement

endif

3. 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

4. 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.'

As distributed, quoting history references is a challenge. Consider:

% mail adec23!alberta!pixel.Convex.COM!tchrist

alberta!pixel.Convex.COM!tchri: Event not found.

5. 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 the 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!

6. 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

The ad hoc parsing csh employs fouls you up in other places

as well. Consider:

% alias foo 'echo hi' ; foo

foo: Command not found.

% foo

hi

7. 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???

Here's another one:

% mkdir tst

% cd tst

% touch '[foo]bar'

% foreach var ( * )

> echo "File named $var"

> end

foreach: No match.

8. SUMMARY

While some vendors have fixed some of the csh's bugs (the tcsh also does

much better here), many have added new ones. Most of its problems can

never be solved because they're not actually bugs per se, but rather the

direct consequences of braindead design decisions. It's inherently flawed.

Do yourself a favor, and if you *have* to write a shell script, do it in the

Bourne shell. It's on every UNIX system out there. However, behavior

can vary.

There are other possibilities.

The Korn shell is the preferred programming shell by many sh addicts,

but it still suffers from inherent problems in the Bourne shell's design,

such as parsing and evaluation horrors. The Korn shell or its

public-domain clones and supersets (like bash) aren't quite so ubiquitous

as sh, so it probably wouldn't be wise to write a sharchive in them that

you post to the net. When 1003.2 becomes a real standard that companies

are forced to adhere to, then we'll be in much better shape. Until

then, we'll be stuck with bug-incompatible versions of the sh lying about.

The Plan 9 shell, rc, is much cleaner in its parsing and evaluation; it is

not widely available, so you'd be significantly sacrificing portability.

No vendor is shipping it yet.

If you don't have to use a shell, but just want an interpreted language,

many other free possibilities present themselves, like Perl, REXX, TCL,

Scheme, or Python. Of these, Perl is probably the most widely available

on UNIX (and many other) systems and certainly comes with the most

extensive UNIX interface. Increasing numbers vendors ship Perl with

their standard systems. (See the comp.lang.perl FAQ for a list.)

If you have a problem that would ordinarily use sed or awk or sh, but it

exceeds their capabilities or must run a little faster, and you don't want

to write the silly thing in C, then Perl may be for you. You can get

at networking functions, binary data, and most of the C library. There

are also translators to turn your sed and awk scripts into Perl scripts,

as well as a symbolic debugger. Tchrist's personal rule of thumb is

that if it's the size that fits in a Makefile, it gets written in the

Bourne shell, but anything bigger gets written in Perl.

See the comp.lang.{perl,rexx,tcl} newsgroups for details about these

languages (including FAQs), or David Muir Sharnoff's comparison of

freely available languages and tools in comp.lang.misc and news.answers.

NOTE: Doug Hamilton <hamilton@bix.com> has a program that he sells for

profit for little toy non-UNIX systems. He calls it 'csh' or the

'hamilton csh', but it's not a csh as it's neither bug nor feature

compatible with the real csh. Actually, he's fixed a great deal, but

in doing so, has created a totally different shell.

--

Tom Christiansen Perl Consultant, Gamer, Hiker tchrist@mox.perl.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有