From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18331 invoked from network); 18 Mar 1999 15:24:58 -0000 Received: from sunsite.auc.dk (130.225.51.30) by ns1.primenet.com.au with SMTP; 18 Mar 1999 15:24:58 -0000 Received: (qmail 17317 invoked by alias); 18 Mar 1999 15:24:31 -0000 Mailing-List: contact zsh-workers-help@sunsite.auc.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 5855 Received: (qmail 17263 invoked from network); 18 Mar 1999 15:24:27 -0000 From: "Andrej Borsenkow" To: "Peter Stephenson" , "Zsh hackers list" Subject: Final touch? RE: PATCH: more substitution documentation Date: Thu, 18 Mar 1999 18:23:37 +0300 Message-ID: <004301be7153$4b4e75d0$21c9ca95@mowp.siemens.ru> MIME-Version: 1.0 Content-Type: text/plain; charset="koi8-r" Content-Transfer-Encoding: 7bit X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook IMO, Build 9.0.2416 (9.0.2910.0) Importance: Normal In-Reply-To: <9903180916.AA38484@ibmth.df.unipi.it> X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2014.211 I think, there is a couple more things that need to be explicitly stated. 1. Nested substitution: 1.1 substitution is done reqursively, including implicit word splitting if SH_WORD_SPLIT is set. This may be obvious, but it is not so in manual. (I believed for a long time, that field splitting is done once after all is done) 1.2 The result of substitution is a *list* (possibly empty or with having only one element). 1.3 Implicit joinig in quotes happens by *outer* subst when it is going to use the value; not by *inner* subst after the value is computed. Again, I always believed, (@) prevents *outer* level from joining words (hence all this confusion). That explains (for me): itsrm2% foo=(a b c d) itsrm2% args "${(@)foo[2,3]}" 2 b c First the foo[2,3] is taken. Because of (@) it is not joined. This is still vague, as we actually have two lists here - $foo and $foo[2,3]. It seems, that foo[2,3] is treated as a single entity. It probably needs to be explained too. That is, the difference betwee foo[...] and ${...}[...]. itsrm2% args "${${(@)foo}[2,3]}" 1 b Outer substitution first joins the list. itsrm2% args "${(@)${foo}[2,3]}" 0 Inner subst does join the list foo (as it is in quotes) - outer one does *not* join it - and we get a list with one word. Rules 1.2 and 1.3. 2. (@) flag In double quotes, it prevents the words of list that results from inner subst to be joined and converted to scalar, even if list has only single word (this is very important)!! That is, even if inner subst results in one word, it still treated as list (array) with one word. 3. Splitting To my great suprise I found, that splitting works even in double quotes!!! itsrm2% args "${(f)$(print "a\nb\nc")}" 3 a b c itsrm2% foo=axbxc itsrm2% args "${(s/x/)foo}" 3 a b c foo="a b c" itsrm2% args "$=foo" 3 a b c That is, no (@) is needed in first case (that is also logical, if we take the meaning of (@) as in 2). Again, it should be mentioned explicitly. This is also logical, if we assume, that joinig occurs in outer subst - as here we have no outer subst at all :-) 4. $= meaning As you see, the spplitting, that is done by $= is *not* the same as default field splitting with SH_WORD_SPLIT. The latter does not happen in double quotes - the former does. I also think it is O.K. - but then, the wording in manual must be changed. Not "turns on SH_WORD_SPLIT" - but "performs word splitting using the same rules as SH_WORD_SPLIT". Looking back, this makes the whole story probably predictable :-) this also explains difference between "${foo[1]}" and "${${(@)foo}[1]}". foo[1] is treated as single entity and results in first elemnt of foo. In the latter case, first value of foo is taken (list), that is then passed as list ((@) flag) to upper subst; that joins the list together (no (@)) and treats it as scalar. Nice. To make the outer treat list as list (array) you need te second (@) - exactly as Sven said. So, the whole for a ${(flags)var-mods} looks like 1. take the value of var. The result is list (array) of words (may be empty or having only one element) 2. If this is quoted and no (@) is present, join the list with the first character if IFS (I think, it is correct? Not always with space?) thus producing a single word (again, actually a list with single word) 3. apply mods separately for every word in list 4. join the words again if (j) is present 5. split using (s) or $= if present 6. If no $= or (s) is present and the whole is not quoted, apply SH_WORD_SPLIT: itsrm2% foo="x y:a b" itsrm2% setopt shwordsplit itsrm2% args ${(s/:/)foo} 2 x y a b itsrm2% args ${foo} 3 x y:a b 7. the result is again a (possibly empty) list of words. If the whole is not quoted, the empty words are removed The steps 1-7 are done recursively for every nested substitution (I hate this word - spelling, that is :-) And a little comment above about subscription. cheers /andrej