jeff (04/15/83)
I kinda like this one. 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. Now explain the following: - Suppose you were to comment out the "set noglob" statement. Why does this swap the first two arguments? - Suppose you change the second argument from "-2" to "2". Why does this...? You have 30 minutes to complete this exercise. If you find the answer, would you kindly let me know? Jeff Stearns ...!decvax!microsoft!fluke!jeff John Fluke Mfg. Co., Everett WA. (206) 356-5064
donn (04/16/83)
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@nprdc