Path: utzoo!utgpu!news-server.csri.toronto.edu!bonnie.concordia.ca!uunet!world!ksr!tim From: tim@ksr.com (Tim Peters) Newsgroups: comp.unix.shell Subject: Re: How does the ksh ENV "trick" work? Message-ID: <3732@ksr.com> Date: 27 May 91 08:28:13 GMT References: <1991May27.054451.24232@brolga.cc.uq.oz.au> Sender: news@ksr.com Organization: Kendall Square Research Corp. Lines: 121 In article <1991May27.054451.24232@brolga.cc.uq.oz.au> eric@brolga.cc.uq.oz.au (Eric Halil) writes: > In "The Kornshell Command and Programming Language" by Morris I. Bolsky and > David G. Korn, Prentice-Hall, 1989, ISBN 0-13-516972-0, page 78 they give: > > export FILE=$HOME/.kshrc > # The subscript below evaluates to 0 when interactive. > ENV='${FILE[(_$-=0)+(_=1)-_${-%%*i*}]}' > >as a easy way to stop your .kshrc being evaluated when it's an not an >interactive shell. Can someone explain in detail how this works? Patience! It's a long sequence of obscure tricks, and it helps to start backwards. So, to start at the end, if a varible VAR is defined in ksh, then ${VAR[0]} has the same value as $VAR (try it! -- a scalar variable in ksh is treated much like a 1-element array). Thus having set FILE to $HOME/.kshrc, ${FILE[0]} is also $HOME/.kshrc, and ${FILE[1]} is undefined (returns a null string, so long as nounset (-u) hasn't been enabled). Next, ENV is evaluated when ksh starts up. The man page is pretty clear about this, so suffice it to say that if you can arrange that ENV evaluate to $HOME/.kshrc if the shell is interactive, and to a null string if the shell is not interactive, then you're done (if ENV evaluates to a null string, no file will be read up since no file whose name is a null string will be found). So we're all set if ENV evaluates to ${FILE[0]} if the shell is interactive and to ${FILE[1]} if it's not. The guts of the long expression does just that: (_$-=0)+(_=1)-_${-%%*i*} evaluates to 0 if the shell is interactive and to 1 if it's not. To see how that works, break the expression up so it's clearer: (_$-=0) + (_=1) - _${-%%*i*} The first term is _$-=0 and this does two things: 1) As a crucial side-effect, sets to 0 the value of the variable whose name is the result of evaluating _$- (more on that below). 2) Evaluates to 0. Recall that $- by itself evaluates to the set of flags with which the shell was invoked. E.g., $- is typically "ismh" for interactive shells (try doing "print $-" and see what you get). The precise set of flags isn't really important except that it will have an "i" in it if & only if the shell is interactive. Executing the "_$-=0" part creates a new variable with underscore as the first letter of its name and the set of flags as the remaining letters in its name. So, e.g., if $- is ismh, this part of the expression sets the variable _ismh to 0. Next, the term (_=1) is evaluated. This again does two things: 1) As a crucial side-effect, sets the variable whose name is a single underscore to the value 1. 2) Evaluates to 1. Next the 0 from evaluating the first term is added to the 1 from evaluating the second term, and 0+1 = 1. So the long subscript expression (_$-=0) + (_=1) - _${-%%*i*} has so far been reduced to 1 - _${-%%*i*} Courage! We're almost done . The only remaining step is to puzzle out what _${-%%*i*} does. First look at the ${-%%*i*} part (i.e., ignore the underscore for a while). ${-%%*i*} is just an ordinary instance of the "expand a variable removing the longest matching suffix" construct: it expands to the value of $-, removing the longest suffix matching pattern *i* (note: you could just as well use "##" instead of "%%" in this context): - If $- has an "i" in it, the longest suffix matching *i* is the entire string, hence ${-%%*i*} evaluates to a null string. - If $- does not have an "i" in it, no suffix matches *i*, hence ${-%%*i*} evaluates to $-. Finally, the value of ${-%%*i*} is attached to _, and the resulting variable is evaluated: - If $- has an "i" in it, _${-%%*i*} first evaluates to plain _, and the variable whose name is _ was set to 1 as a side-effect of evaluating the second term. So the whole subscript expression evaluates to 1-1 = 0, and ${FILE[0]} = $HOME/.kshrc is read up. - If $- does not have in "i" in it _${-%%*i*} first evaluates to _$- (where the $- part is whatever set of flags the shell was invoked with), and the variable whose name is *that* was set to 0 as a side-effect of evaluating the first term. So the whole subscript expression in this case evaluates to 1-0 = 1, and ${FILE[1]} evaluates to a null string and so no file is read up. Revolting, isn't it ? And to think I used to enjoy stuff like this ... suspecting-obscurity-is-the-secret-end-as-well-as-the-means-ly y'rs - tim Tim Peters Kendall Square Research Corp tim@ksr.com, ksr!tim@uunet.uu.net