Argument-swap feature within csh
utzoo!decvax!harpo!floyd!cmcl2!philabs!sdcsvax!sdchema!donn
utzoo!decvax!harpo!floyd!cmcl2!philabs!sdcsvax!sdchema!donn
Sat Apr 16 04:02:41 AEST 1983
Reference: fluke.859
Jeff Stearns says:
I kinda like this one.
So do I -- it reminds me of an experience I had when I was evaluating
the C-shell for use at Informatics (the contractor at NASA Life
Sciences at Moffett Field, Sunnyvale, California) way back in 1980.
Even though the bug I found at that time has since been repaired, I
can't resist telling everyone about it because it was so incredibly
weird. It instilled in me great respect for the complexity of large
programs. To make up for this di(trans?)gression I will first answer
Jeff's plea for an explanation of his own problem (and I will even give
the relevant fix!). Yes, this takes less than 30 minutes to solve; if
you still want to solve it yourself, read no further.
Here's a fun test for your next prospective job candidate...
Ask her what the following csh script does. Just for fun, ask
yourself, too.
#! /bin/csh -f
set noglob
echo '1' >/tmp/foo
echo `/bin/cat /tmp/foo` -2 3
STOP. Do not turn the page until you have the answer.
===============================================================
In case you don't have a 4.1BSD UNIX system, I'll reproduce the
output below:
% bug
-2 1 3
%
Did you get that? Good...
You have 30 minutes to complete this exercise. If you find the
answer, would you kindly let me know?
Actually this presentation of the bug is a bit misleading. A little
experimentation shows that you can also do the following, interactively:
% set noglob
% echo `echo 5 4 3` 2 1
2 3 4 5 1
%
The problem here is that the C-shell has sorted the output of the
command expansion in backquotes as though it was the output of a "glob"
or pattern matching operation. Interestingly, the sort also includes
the first argument following the command expansion. What has happened
is that the C-shell has marked the command expansion for possible
"globbing" and hence sorting, but since "noglob" is set, it decides
that can't do the sort anyway and it skips on to the next argument.
Unfortunately it "forgets" to reset its sort pointer, and as a result
instead of the C-shell (redundantly) sorting the single argument
following the command expansion, it sorts the whole string consisting
of the command expansion plus the following argument. The change to
fix this trivial bug must be made in sh.glob.c (I have prettied this
"diff" up a bit, mind you):
*** sh.glob.c.old Sat Apr 16 01:13:23 1983
--- sh.glob.c Sat Apr 16 01:16:31 1983
***************
*** 66,72
printf("backp done, acollect'ing\n");
#endif
for (i = 0; i < pargc; i++)
! if (noglob)
Gcat(pargv[i], "");
! else
acollect(pargv[i]);
--- 66,77 -----
printf("backp done, acollect'ing\n");
#endif
for (i = 0; i < pargc; i++)
! if (noglob) {
! /*
! * Bug fixed -- prevent sorting of backquote
! * substitutions when noglob is set.
! * Donn Seeley, UCSD Chemistry, 4/15/83.
! */
Gcat(pargv[i], "");
! sortbas = &gargv[gargc];
! } else
acollect(pargv[i]);
Now, with that out of the way, let me quote my own bug report from 1980:
------------------------------------------------------------------------
C-Shell Bugs / August 15, 1980 / Page 7
6. Argument lists and nonomatch
The nonomatch cshell variable is supposed to prevent the cshell from
stopping with an error when it encounters an expression with *, ? or []
(wild cards) that matches no existing filename. Strange things happen
to the ordering of elements in an argument list when this matching
process ("globbing") fails, however. The cshell leaves the original
wild card expressions untouched when this occurs, but unfortunately it
still tries to sort the patterns just as though they had successfully
matched filenames. In particular sublists consisting of zero or more
consecutive unmatched wild card arguments followed by an argument with
no wild cards are ASCII sorted in the list:
% mkdir junk
% cd junk
% set nonomatch
% echo 8* 7* 5* 6 1* 3* 2 4* 0*
5* 6 7* 8* 1* 2 3* 4* 0*
%
This has peculiar consequences for 'foreach' loops. Since cshell input
is not parsed, left and right parentheses are just arguments which
receive certain special treatment. The cshell checks to see that
parentheses are balanced, and the 'foreach' statement checks to make
sure that all its list arguments are in parentheses, but it does this
checking before it does argument sorting. When unmatched wild card
arguments appear at the end of the argument list, the cshell sorts the
sublist of arguments that ends in the final right parenthesis. Since
the right parenthesis comes before the alphabet in the ASCII character
set, it is usually transported by the sort to the beginning of the
sublist and some wild card argument comes to terminate the list; the
cshell throws this argument away, thinking it to be a right
parenthesis, and the right parenthesis becomes one of the values taken
on by the 'foreach' variable. This can be very mysterious.
% foreach i ( z* x* w* )
? echo "$i"
? end
)
w*
x*
%
------------------------------------------------------------------------
I guess I just have a strange sense of humor.
Donn Seeley UCSD Chemistry Dept. RRCF ucbvax!sdcsvax!sdchema!donn
(619) 452-4016 sdamos!donn at nprdc
More information about the Comp.bugs.4bsd.ucb-fixes
mailing list