From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10805 invoked from network); 9 Feb 2001 01:25:28 -0000 Received: from sunsite.dk (130.225.51.30) by ns1.primenet.com.au with SMTP; 9 Feb 2001 01:25:28 -0000 Received: (qmail 23616 invoked by alias); 9 Feb 2001 01:25:08 -0000 Mailing-List: contact zsh-users-help@sunsite.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 3611 Received: (qmail 23604 invoked from network); 9 Feb 2001 01:25:06 -0000 From: Deborah Ariel Pickett Message-Id: <200102090123.MAA55479@bruce.csse.monash.edu.au> Subject: Word splitting in zsh To: zsh-users@sunsite.dk Date: Fri, 9 Feb 2001 12:23:59 +1100 (EST) X-Mailer: ELM [version 2.5 PL3] MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Hiya, I've come across this little problem in zsh when I run it under setopt SHWORDSPLIT (not that this is something I normally do). What it boils down to is that in constructs like ${variable-word} (where "-" is any of the characters that can go in that place - e.g., "-", "+", "=") the shell doesn't seem to be honouring double quotes the way the manpage says. Here's the relevant sections in the manpage: [...] (Parameters) @ In double quotes, array elements are put into sepa- rate words. E.g., "${(@)foo}" is equivalent to "${foo[@]}" and "${(@)foo[1,2]}" is the same as "$foo[1]" "$foo[2]". [...] (Parameter expansion) ${name:+word} If name is set and is non-null then substitute word; otherwise substitute nothing. [...] Note that double quotes may appear around nested substitu- tions, in which case only the part inside is treated as quoted; for example, ${(f)"$(foo)"} quotes the result of $(foo), but the flag `(f)' (see below) is applied using the rules for unquoted substitutions. Note further that quotes are themselves nested in this context; for example, in "${(@f)"$(foo)"}", there are two sets of quotes, one surrounding the whole expression, the other (redundant) surrounding the $(foo) as before. With these two bits together, the POSIX and Bourne shells can make a generic "any number of arguments, including zero" by using the form ${1+"$@"} (i.e., if $1 is set, substitute "$@", otherwise substitute nothing). Trying that in zsh, I get this: bruce ~ % echo $ZSH_VERSION 3.1.6 # (But this also applies in 3.1.9) bruce ~ % setopt alwaystoend noappendhistory autocd noautomenu autonamedirs autopushd autoresume braceccl noclobber completeinword correct extendedglob noflowcontrol globdots histexpiredupsfirst histignoredups histnostore ignoreeof interactive nolistbeep longlistjobs monitor numericglobsort promptsubst pushdignoredups pushdminus pushdsilent pushdtohome shinstdin zle bruce ~ % setopt shwordsplit # Now splitting is done like in other shells. bruce ~ args() function >{ function >for x function for >do function for >echo "'$x'" function for >done function >} bruce ~ % args "a1 a2 a3" b c 'a1 a2 a3' 'b' 'c' # Ok, that's what we expected. bruce ~ % args "$@" # Acceptable, but Bourne sh would print a single blank entry here, since # there's a pair of quotes. bruce ~ % args ${1+"$@"} # This is the Proper Bourne Shell way to do it. bruce ~ % set "a1 a2 a3" b c bruce ~ % args "$@" 'a1 a2 a3' 'b' 'c' # Fine . . . bruce ~ % args ${1+"$@"} 'a1' 'a2' 'a3' 'b' 'c' # What?? The $@ was in quotes, why was "a1 a2 a3" split? bruce ~ % bash --posix # Let's try the same under a POSIX shell. bash-2.03$ args() > { > for x > do > echo "'$x'" > done > } bash-2.03$ set "a1 a2 a3" b c bash-2.03$ args ${1+"$@"} 'a1 a2 a3' 'b' 'c' # Here it does it the correct way. So . . am I misunderstanding how double quotes are propagated through ${} constructs in zsh? Or is this a bona fide bug? Whatever the answer, this is something that doesn't work the same as in the Bourne shell. Should it? The only hint of an answer comes in this section of the manpage: 1. Nested Substitution If multiple nested ${...} forms are present, sub- stitution is performed from the inside outwards. At each level, the substitution takes account of whether the current value is a scalar or an array, whether the whole substitution is in double quotes, and what flags are supplied to the current level of substitution, just as if the nested substitution were the outermost. The flags are not propagated up to enclosing substitutions; the nested substitu- tion will return either a scalar or an array as determined by the flags, possibly adjusted for quoting. All the following steps take place where applicable at all levels of substitution. Note that, unless the `(P)' flag is present, the flags and any subscripts apply directly to the value of the nested substitution; for example, the expansion ${${foo}} behaves exactly the same as ${foo}. This makes some sense, since these produce different results: bruce ~ % args "${@}" 'a1 a2 a3' 'b' 'c' bruce ~ % args "${${@}}" 'a1 a2 a3 b c' though I wonder if they ought to, since this disagrees with the last sentence about ${${foo}} and ${foo}. -- Debbie Pickett http://www.csse.monash.edu.au/~debbiep debbiep@csse.monash.edu.au "Look at me; I will never pass for a perfect bride, or a perfect daughter. Can it be I'm not meant to play this part? Now I see that if I were truly to be myself, I would break my family's heart." - Reflection, _Mulan_