nose@nbires.UUCP (Steve Dunn) (03/25/86)
I've been foolish enough to try to write a shell script lately. I'm using the C-shell on 4.2 berkley UNIX. Since both UNIX and its documentation are for me just a bit cryptic (Ahem) I can't even be sure what's a bug and what's actually really intended to be that way, so I'm posting this to both bugs and wizards. I am interested in anyone who has solutions to or explanations for any of these problems. 1. if tests: the statement: if ($arg == '-b') echo 'UNIX is fun' Will get the error "If: missing filename" if $arg happens to equal -x or -e or any of the other constructs used to test file attributes. The statement will NOT fail if $arg happens to equal other reserved words such as "if" or "foreach". I did find a kludge to get around this but it makes be want to rip out my intestines with a fork. (Well actually its not quite *that* bad...) The statement can be replaced by this one: if (x$arg == 'x-b') echo 'UNIX is fun' Is there a better way to do this and why does this happen in the first place? 2: Count of number of words in a variable (Or when is nothing something) This: set hosed = '' echo $#hosed yields the result '1' It seems to me that a variable with null contents has ZERO words not one 3: Logical not operator According to the csh man page the logical not operator "!" is available. Unfortunately the statements (in a shell script) set lights_on = 1 if (!$lights_on) echo 'nobody home' yield the message "0: event not found". Apparently the shell is trying to do a history substitution instead of a negation. I have tried all manner of quoting to get around this - nothing works. Well then, given that "!" is used both to signal history substitutions and as a logical not operator, how can you tell which the shell will choose to do in a given situation? -Steve "If I only had a brain..." Dunn
woods@hao.UUCP (Greg Woods) (03/26/86)
> the statement: > > if ($arg == '-b') echo 'UNIX is fun' ...should in fact be: if ("$arg" == "-b") echo 'UNIX is fun' This really is a feature, not a bug, and I actually have some shell scripts that use it to test various kinds of access to files for various reasons, such as the following trivial example: foreach access (e r w x) if (-$access "$file") echo $access access is permitted to $file end Moral of story: ALL strings used in if tests should be quoted. Double quotes still permits variable substitution, single quotes inhibit it (believe it or not, this IS actually documented in the csh(1) man page! :-) > 2: Count of number of words in a variable (Or when is nothing something) > > This: > > set hosed = '' > echo $#hosed > > yields the result '1' But of course! The variable has one value: a null string. And, if you do set hosed=( '' junk) then what do you suppose $#hosed is? If you got 2, drink a potion of raise level and read on! :-) If you do set hosed echo $#hosed THEN you will get 0. The difference? A null string is different from no value at all. This too has it's uses, such as when each word of a variable stands for an attribute of the object represented by the variable, and a null string means that attribute does not exist (i.e. a kludgy implentation of a structure in a shell script. And yes, I'm masochistic; I actually have real scripts that use this too :-) > 3: Logical not operator > > According to the csh man page the logical not operator "!" is available. Also according to the man page, any non-space character after ! invokes the history mechanism. While it does not (and probably should) say this explicitly in the documentation for the ! not operator, it follows from this that what is needed is a space after the ! when using it as a unary logical operator, e.g. > set lights_on = 1 > if (!$lights_on) echo 'nobody home' set lights_on=1 if (! $lights_on) echo 'nobody home' The best way to implement Boolean flags under csh is much simpler: the variable exists or it doesn't. The construct $?var returns 1 if var is defined and 0 if it isn't, and is NOT an error if var is undefined. I.e. your above example converts to: set lights_on if (! $?lights_on) echo 'nobody home' Hope this helps. --Greg
nose@nbires.UUCP (Steve Dunn) (03/26/86)
Greg Woods writes in response to my article on c-shell weirdness: > > > 2: Count of number of words in a variable (Or when is nothing something) > > > > This: > > > > set hosed = '' > > echo $#hosed > > > > yields the result '1' > > But of course! The variable has one value: a null string. And, if you do > > set hosed=( '' junk) > > then what do you suppose $#hosed is? If you got 2, drink a potion of raise > level and read on! :-) If you do > > set hosed > echo $#hosed > > THEN you will get 0. The difference? A null string is different from no value > at all. This too has it's uses, such as when each word of a variable stands > for an attribute of the object represented by the variable, and a null string > means that attribute does not exist (i.e. a kludgy implentation of a > structure in a shell script. And yes, I'm masochistic; I actually have > real scripts that use this too :-) > Sorry, I tried the example that is supposed to yield zero and I got one instead. Furthermore, according to the manual page for csh under the set command "The second form [set name] sets name to the null string" The answer is that you can't have a variable with 0 words at all. This fact I find counter-intuitive and undocumented ---- The answers Greg gave to my questions on if tests and the not operator were correct and very helpful although I still can't figure out where the documentation says that if a variable name in an if test expands to one of -r, -w, -x etc, the shell will interpet the expanded variable name as a command. -Steve "Wrong Way" Dunn
woods@hao.UUCP (Greg Woods) (03/27/86)
> > set hosed > > echo $#hosed > > > > THEN you will get 0. > > Sorry, I tried the example that is supposed to yield zero and I got one > instead. > > The answer is that you can't have a variable with 0 words at all. > This fact I find counter-intuitive and undocumented I stand corrected. It seems that $#var is either an error or a positive integer. Counterintuitive is debatable, however; a variable with no words is kind of like saying something that is nothing. The only exception I am aware of to this is that $#argv CAN be zero if it occurs in a shell which was given no arguments (which includes your login shell; try it). THIS is what is counter-intutive to ME, that argv behaves differently than all other variables in this respect. > I still can't figure out where > the documentation says that if a variable name in an if test expands to > one of -r, -w, -x etc, the shell will interpet the expanded variable name > as a command. The C-shell is a VERY complicated program, obviously; it would be nearly impossible to document how it would behave on every conceivable possibility. But in any case, it DOES say that parsing and substitutions (which presumably includes variable substitutions) are performed before the command is executed. --Greg
greg@ncr-sd.UUCP (Greg Noel) (03/27/86)
In article <2024@hao.UUCP> woods@hao.UUCP (Greg Woods) writes: >> > set hosed >> > echo $#hosed >> > THEN you will get 0. >> Sorry, I tried the example that is supposed to yield zero and I got one >> instead. >> The answer is that you can't have a variable with 0 words at all. >> This fact I find counter-intuitive and undocumented > I stand corrected. It seems that $#var is either an error or a positive >integer. Counterintuitive is debatable, however; ..... No, there is a way to get a C shell variable with zero words: set hosed = () Counterintuitive is relative -- this was obvous to me; but then, I wasn't trying to do it, it was an accidential side-effect of doing: set something = (`some command`) if $#something ...... -- -- Greg Noel, NCR Rancho Bernardo Greg@ncr-sd.UUCP or Greg@nosc.ARPA
wyatt@cfa.UUCP (Bill Wyatt) (03/28/86)
> ... If you do > > set hosed > echo $#hosed > > THEN you will get 0. The difference? A null string is different from no value > at all. ... Small problem: on my system (Ultrix 32m 1.1) the above gives 1, not 0. No, I did an `unset hosed' first to make sure no garbage was left behind. -- Bill UUCP: {seismo|ihnp4|cmcl2}!harvard!talcott!cfa!wyatt Wyatt ARPA: wyatt%cfa.UUCP@harvard.HARVARD.EDU
chris@umcp-cs.UUCP (Chris Torek) (03/28/86)
In article <2024@hao.UUCP> woods@hao.UUCP writes: >It seems that $#var is either an error or a positive integer. Not so: % set foo % echo $#foo 1 % set foo=() % echo $#foo 0 % -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1415) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu
jpn@teddy.UUCP (03/28/86)
>> set hosed >> echo $#hosed >> >> THEN you will get 0. > >Small problem: on my system (Ultrix 32m 1.1) the above gives 1, not 0. Uh, all csh variables (except argv) will always have ONE element unless you used the set notation when setting their value. The way to create a variable with zero elements is: set hosed = ()
roger@ll-xn.ARPA (Roger Hale) (03/28/86)
In article <196@cfa.UUCP>, wyatt@cfa.UUCP (Bill Wyatt) writes: > > ... If you do > > > > set hosed > > echo $#hosed > > > > THEN you will get 0. > > Small problem: on my system (Ultrix 32m 1.1) the above gives 1, not 0. set foo=() echo $#foo gives me 0. (4.2bsd vax.) I suspect it will elsewhere too. Roger Hale Internet: roger@ll-xn.arpa
woods@hao.UUCP (Greg Woods) (03/29/86)
> No, there is a way to get a C shell variable with zero words: > set hosed = () > Counterintuitive is relative -- this was obvous to me; but then, I wasn't > trying to do it, it was an accidential side-effect of doing: > set something = (`some command`) > if $#something ...... Well, I still think Steve Dunn's postings were more whiny than was necessary, but I'm glad he posted them anyway, because now I've learned something about a program that I use extensively that I didn't know before. --Greg
jsdy@hadron.UUCP (03/29/86)
In article <676@nbires.UUCP> nose@nbires.UUCP (Steve Dunn) writes: > if ($arg == '-b') echo 'UNIX is fun' >Will get the error "If: missing filename" if $arg happens to equal >-x or -e or any of the other constructs used to test file attributes. > if (x$arg == 'x-b') echo 'UNIX is fun' >Is there a better way to do this and why does this happen in the first >place? [The rest of this was ably answered elsewhere. HOWEVER ...] Consider what the command line is when $arg is -e or -x or whatever: if (-e == '-b') ... Now, doesn't that just look like it's asking to evaluate -e on file "==", or something like that? Of course the parser recognises "==" as a relation, and so complains instead that there's no file name. Your alternative is actually a venerable shell-script idiom to cancel the flag effect of the "-". However, you really should put $arg in double-quotes to negate the effect of an in-valid string: set arg = "-b -e" if (x$arg == '-b') becomes if (x-b -e == '-b') with who knows what syntax error reports. I'd use: if ("X$arg" == "X-b") ... -- Joe Yao hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}
jsdy@hadron.UUCP (03/29/86)
In article <2024@hao.UUCP> woods@hao.UUCP (Greg Woods) writes: >> Sorry, I tried the example that is supposed to yield zero and I got one >> instead. >> The answer is that you can't have a variable with 0 words at all. >> This fact I find counter-intuitive and undocumented Try set hosed = (). This is suggested by woods' own earlier posting. This is the way to get $#hosed == 0. Anything else (including just set hosed) sets the variable to one or more words. >> I still can't figure out where >> the documentation says that if a variable name in an if test expands to >> one of -r, -w, -x etc, the shell will interpet the expanded variable name >> as a command. See my earlier posting. What do you expect csh to do with if (-e == -b) ??? [;-)] BTW, why is it that woods@hao's responses keep getting here before the questions from nbires? [rhetorical question, mostly.] -- Joe Yao hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}
maartenj@ark.UUCP (03/30/86)
In article <2024@hao.UUCP> woods@hao.UUCP writes: >> > set hosed >> > echo $#hosed >> > >> > THEN you will get 0. >> >> Sorry, I tried the example that is supposed to yield zero and I got one >> instead. >> >> The answer is that you can't have a variable with 0 words at all. >> This fact I find counter-intuitive and undocumented > > I stand corrected. It seems that $#var is either an error or a positive >integer. Counterintuitive is debatable, however; a variable with no words >is kind of like saying something that is nothing. The only exception >I am aware of to this is that $#argv CAN be zero if it occurs in a shell >which was given no arguments (which includes your login shell; try it). >THIS is what is counter-intutive to ME, that argv behaves differently than >all other variables in this respect. Try : set hosed = () echo $#hosed This will give you 0. The point is the definitions of a `word'. A word is defined as being separated by a tab, space or newline accept when the string, containing these characters, is enclosed in `'' or `"' (with one exception when you do something like: "`cat /etc/passwd`" this will force new words at newlines). The actual syntax is of `set' is : set arg = ( wordlist ) when you only set the arg to one word you can leave out the `(' and `)': set arg = word Finally you have the abbreviation : set arg This is exactly the same as set arg = '' e.i. it will set arg to a null string. So $#arg will give the number of words in $arg. -- Maarten Jan Huisjes. (maartenj@vu44.UUCP) {seismo|decvax|philabs}!mcvax!vu44!maartenj
greg@ncr-sd.UUCP (Greg Noel) (03/31/86)
In article <713@ark.UUCP> maartenj@vu44.UUCP (Huisjes Maarten Jan) writes: > > ... (a very good technical explaination of how words are parsed) ... > >The actual syntax is of `set' is : > set arg = ( wordlist ) >when you only set the arg to one word you can leave out the `(' and `)': > set arg = word >Finally you have the abbreviation : > set arg >This is exactly the same as > set arg = '' >e.i. it will set arg to a null string. Indeed, the theory is that the above is true. This is a nit, but in actual practice, the C shell uses different paths to evaluate the different cases. They are supposed to be equivalent, but sometimes they are not. I once got bitten when I did "set path = /special/commands/directory" (case two above). It turns out that the code that checks when "path" is set and exports into the PATH environment variable is only present in the flow for the first case above. Instead, you have to say "set path = ( /special/commands/directory )" to get it to work. I reported this bug and changed it in the C shell I had; I hope it's been fixed. I suppose that's a point for evolution by design......... -- -- Greg Noel, NCR Rancho Bernardo Greg@ncr-sd.UUCP or Greg@nosc.ARPA
lef@nlm-vax.ARPA (Larry Fitzpatrick) (04/02/86)
In article <344@hadron.UUCP> jsdy@hadron.UUCP (Joseph S. D. Yao) writes: >Your alternative is actually a venerable shell-script idiom to cancel >the flag effect of the "-". However, you really should put $arg in >double-quotes to negate the effect of an in-valid string: > set arg = "-b -e" > if (x$arg == '-b') >becomes > if (x-b -e == '-b') >with who knows what syntax error reports. I'd use: > if ("X$arg" == "X-b") ... if ("$arg" == "-b") echo is sufficient regards, fitz lef@nlm-vax