📄 341.html
字号:
<br>
In the Bourne shell, you can open or dup arbitrary file descriptors.<br>
For example,<br>
<br>
exec 2>errs.out<br>
<br>
means that from then on, stderr goes into errs file.<br>
<br>
Or what if you just want to throw away stderr and leave stdout<br>
alone? Pretty simple operation, eh?<br>
<br>
cmd 2>/dev/null<br>
<br>
Works in the Bourne shell. In the csh, you can only make a pitiful<br>
attempt like this:<br>
<br>
(cmd > /dev/tty) >& /dev/null<br>
<br>
But who said that stdout was my tty? So it's wrong. This simple<br>
operation *CANNOT BE DONE* in the csh.<br>
<br>
<br>
Along these same lines, you can't direct error messages in csh scripts<br>
out stderr as is considered proper. In the Bourne shell, you might say:<br>
<br>
echo "$0: cannot find $file" 1>&2<br>
<br>
but in the csh, you can't redirect stdout out stderr, so you end<br>
up doing something silly like this:<br>
<br>
sh -c 'echo "$0: cannot find $file" 1>&2'<br>
<br>
1b. Reading Files<br>
<br>
In the csh, all you've got is $<, which reads a line from your tty. What<br>
if you've redirected stdin? Tough noogies, you still get your tty, which<br>
you really can't redirect. Now, the read statement<br>
in the Bourne shell allows you to read from stdin, which catches<br>
redirection. It also means that you can do things like this:<br>
<br>
exec 3<file1<br>
exec 4<file2<br>
<br>
Now you can read from fd 3 and get lines from file1, or from file2 through<br>
fd 4. In modern, Bourne-like shells, this suffices:<br>
<br>
read some_var 0<&3<br>
read another_var 0<&4<br>
<br>
Although in older ones where read only goes from 0, you trick it:<br>
<br>
exec 5<&0 # save old stdin<br>
exec 0<&3; read some_var<br>
exec 0<&4; read another_var<br>
exec 0<&5 # restore it<br>
<br>
<br>
1c. Closing FDs<br>
<br>
In the Bourne shell, you can close file descriptors you don't<br>
want open, like 2>&-, which isn't the same as redirecting it<br>
to /dev/null.<br>
<br>
1d. More Elaborate Combinations<br>
<br>
Maybe you want to pipe stderr to a command and leave stdout alone.<br>
Not too hard an idea, right? You can't do this in the csh as I<br>
mentioned in 1a. In a Bourne shell, you can do things like this:<br>
<br>
exec 3>&1; grep yyy xxx 2>&1 1>&3 3>&- | sed s/file/foobar/ 1>&2 3>&-<br>
grep: xxx: No such foobar or directory<br>
<br>
Normal output would be unaffected. The closes there were in case<br>
something really cared about all its FDs. We send stderr to sed,<br>
and then put it back out 2.<br>
<br>
Consider the pipeline:<br>
<br>
A | B | C<br>
<br>
You want to know the status of C, well, that's easy: it's in $?, or<br>
$status in csh. But if you want it from A, you're out of luck -- if<br>
you're in the csh, that is. In the Bourne shell, you can get it, although<br>
doing so is a bit tricky. Here's something I had to do where I ran dd's<br>
stderr into a grep -v pipe to get rid of the records in/out noise, but had<br>
to return the dd's exit status, not the grep's:<br>
<br>
device=/dev/rmt8<br>
dd_noise='^[0-9]++[0-9]+ records (in|out)$'<br>
exec 3>&1<br>
status=`((dd if=$device ibs=64k 2>&1 1>&3 3>&- 4>&-; echo $? >&4) |<br>
egrep -v "$dd_noise" 1>&2 3>&- 4>&-) 4>&1`<br>
exit $status;<br>
<br>
<br>
The csh has also been known to close all open file descriptors besides<br>
the ones it knows about, making it unsuitable for applications that<br>
intend to inherit open file descriptors.<br>
<br>
<br>
2. COMMAND ORTHOGONALITY<br>
<br>
2a. Built-ins<br>
<br>
The csh is a horrid botch with its built-ins. You can't put them<br>
together in many reasonable ways. Even simple little things like this:<br>
<br>
% time | echo<br>
<br>
which while nonsensical, shouldn't give me this message:<br>
<br>
Reset tty pgrp from 9341 to 26678<br>
<br>
Others are more fun:<br>
<br>
% sleep 1 | while<br>
while: Too few arguments.<br>
[5] 9402<br>
% jobs<br>
[5] 9402 Done sleep |<br>
<br>
<br>
Some can even hang your shell. Try typing ^Z while you're sourcing<br>
something, or redirecting a source command. Just make sure you have<br>
another window handy. Or try<br>
<br>
% history | more<br>
<br>
on some systems.<br>
<br>
Aliases are not evaluated everywhere you would like them do be:<br>
<br>
% alias lu 'ls -u'<br>
% lu<br>
HISTORY News bin fortran lib lyrics misc tex<br>
Mail TEX dehnung hpview logs mbox netlib<br>
% repeat 3 lu<br>
lu: Command not found.<br>
lu: Command not found.<br>
lu: Command not found.<br>
<br>
% time lu<br>
lu: Command not found.<br>
<br>
<br>
2b. Flow control<br>
<br>
You can't mix flow-control and commands, like this:<br>
<br>
who | while read line; do<br>
echo "gotta $line"<br>
done<br>
<br>
<br>
You can't combine multiline constructs in a csh using semicolons.<br>
There's no easy way to do this<br>
<br>
alias cmd 'if (foo) then bar; else snark; endif'<br>
<br>
<br>
You can't perform redirections with if statements that are<br>
evaluated solely for their exit status:<br>
<br>
if ( { grep vt100 /etc/termcap > /dev/null } ) echo ok<br>
<br>
And even pipes don't work:<br>
<br>
if ( { grep vt100 /etc/termcap | sed 's/$/###' } ) echo ok<br>
<br>
But these work just fine in the Bourne shell:<br>
<br>
if grep vt100 /etc/termcap > /dev/null ; then echo ok; fi <br>
<br>
if grep vt100 /etc/termcap | sed 's/$/###/' ; then echo ok; fi<br>
<br>
<br>
Consider the following reasonable construct:<br>
<br>
if ( { command1 | command2 } ) then<br>
...<br>
endif<br>
<br>
The output of command1 won't go into the input of command2. You will get<br>
the output of both commands on standard output. No error is raised. In<br>
the Bourne shell or its clones, you would say<br>
<br>
if command1 | command2 ; then<br>
...<br>
fi<br>
<br>
<br>
2c. Stupid parsing bugs<br>
<br>
Certain reasonable things just don't work, like this:<br>
<br>
% kill -1 `cat foo`<br>
`cat foo`: Ambiguous.<br>
<br>
But this is ok:<br>
<br>
% /bin/kill -1 `cat foo`<br>
<br>
If you have a stopped job:<br>
<br>
[2] Stopped rlogin globhost<br>
<br>
You should be able to kill it with<br>
<br>
% kill %?glob<br>
kill: No match<br>
<br>
but<br>
<br>
% fg %?glob<br>
<br>
works.<br>
<br>
White space can matter:<br>
<br>
if(expr)<br>
<br>
may fail on some versions of csh, while<br>
<br>
if (expr)<br>
<br>
works! Your vendor may have attempted to fix this bug, but odds are good<br>
that their csh still won't be able to handle<br>
<br>
if(0) then<br>
if(1) then<br>
echo A: got here<br>
else<br>
echo B: got here<br>
endif<br>
echo We should never execute this statement<br>
endif<br>
<br>
3. SIGNALS<br>
<br>
In the csh, all you can do with signals is trap SIGINT. In the Bourne<br>
shell, you can trap any signal, or the end-of-program exit. For example,<br>
to blow away a tempfile on any of a variety of signals:<br>
<br>
$ trap 'rm -f /usr/adm/tmp/i$$ ;<br>
echo "ERROR: abnormal exit";<br>
exit' 1 2 3 15<br>
<br>
$ trap 'rm tmp.$$' 0 # on program exit<br>
<br>
4. QUOTING<br>
<br>
You can't quote things reasonably in the csh:<br>
<br>
set foo = "Bill asked, "How's tricks?""<br>
<br>
doesn't work. This makes it really hard to construct strings with<br>
mixed quotes in them. In the Bourne shell, this works just fine.<br>
In fact, so does this:<br>
<br>
cd /mnt; /usr/ucb/finger -m -s `ls `u``<br>
<br>
Dollar signs cannot be escaped in double quotes in the csh. Ug.<br>
<br>
set foo = "this is a $dollar quoted and this is $HOME not quoted"<br>
dollar: Undefined variable.<br>
<br>
You have to use backslashes for newlines, and it's just darn hard to<br>
get them into strings sometimes.<br>
<br>
set foo = "this <br>
and that";<br>
echo $foo<br>
this and that<br>
echo "$foo"<br>
Unmatched ". <br>
<br>
Say what? You don't have these problems in the Bourne shell, where it's<br>
just fine to write things like this:<br>
<br>
echo 'This is<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -