# Test parameter expansion. Phew. %prep mkdir parameter.tmp cd parameter.tmp touch boringfile evenmoreboringfile %test foo='the first parameter' bar='the second parameter' print -l $foo ${bar} 0:Basic scalar parameter substitution >the first parameter >the second parameter array1=(the first array) array2=(the second array) print -l $array1 ${array2} 0:Basic array parameter substitution >the >first >array >the >second >array setopt ksharrays print -l $array1 ${array2} unsetopt ksharrays 0:Basic ksharray substitution >the >the setopt shwordsplit print -l $foo ${bar} print -l ${==bar} unsetopt shwordsplit 0:Basic shwordsplit option handling >the >first >parameter >the >second >parameter >the second parameter print $+foo ${+foo} $+notappearinginthistest ${+notappearinginthistest} 0:$+... >1 1 0 0 set1=set1v null1= print ${set1:-set1d} ${set1-set2d} ${null1:-null1d} ${null1-null2d} x print ${unset1:-unset1d} ${unset1-unset2d} x 0:${...:-...} and ${...-...} >set1v set1v null1d x >unset1d unset2d x set2=irrelevant print ${set1:=set1d} ${set2::=set2d} print $set2 wasnull1= wasnull2= print ${wasnull1=wasnull1d} ${wasnull2:=wasnull2d} print $wasnull1 $wasnull2 0:${...:=...}, ${...::=...}, ${...=...} >set1v set2d >set2d >wasnull2d >wasnull2d (print ${set1:?okhere}; print ${unset1:?exiting1}; print not reached;) (print ${null1?okhere}; print ${null1:?exiting2}; print not reached;) 1:${...:?...}, ${...?...} >set1v > ?(eval):1: unset1: exiting1 ?(eval):2: null1: exiting2 print ${set1:+word1} ${set1+word2} ${null1:+word3} ${null1+word4} print ${unset1:+word5} ${unset1+word6} 0:${...:+...}, ${...+...} >word1 word2 word4 > str1='This is very boring indeed.' print ${str1#*s} print ${str1##*s} print $str1##s 0:${...#...}, ${...##...} > is very boring indeed. > very boring indeed. >This is very boring indeed.##s str2='If you'\''re reading this you should go and fix some bugs instead.' print ${str2%d*} print ${str2%%d*} 0:${...%...}, ${...%%...} >If you're reading this you should go and fix some bugs instea >If you're rea str1='does match' str2='does not match' print ${str1:#does * match} print ${str2:#does * match} 0:${...:#...} >does match > array1=(arthur boldly claws dogs every fight) print ${array1:#[aeiou]*} print ${(M)array1:#[aeiou]*} 0:${...:#...}, ${(M)...:#...} with array >boldly claws dogs fight >arthur every str1="$array1" print ${str1/[aeiou]*g/a braw bricht moonlicht nicht the nic} print ${(S)str1/[aeiou]*g/relishe} 0:scalar ${.../.../...}, ${(S).../.../...} >a braw bricht moonlicht nicht the nicht >relishes every fight print ${array1/[aeiou]*/Y} print ${(S)array1/[aeiou]*/Y} 0:array ${.../.../...}, ${(S).../.../...} >Y bY clY dY Y fY >Yrthur bYldly clYws dYgs Yvery fYght str1='o this is so, so so very dull' print ${str1//o*/Please no} print ${(S)str1//o*/Please no} 0:scalar ${...//.../...}, ${(S)...//.../...} >Please no >Please no this is sPlease no, sPlease no sPlease no very dull print ${array1//[aeiou]*/Y} print ${(S)array1//[aeiou]*/Y} 0:array ${...//.../...}, ${(S)...//.../...} >Y bY clY dY Y fY >YrthYr bYldly clYws dYgs YvYry fYght print ${array1:/[aeiou]*/expletive deleted} 0:array ${...:/...} >expletive deleted boldly claws dogs expletive deleted fight str1='a\string\with\backslashes' str2='a/string/with/slashes' print "${str1//\\/-}" print ${str1//\\/-} print "${str2//\//-}" print ${str2//\//-} 0:use of backslashes in //-substitutions >a-string-with-backslashes >a-string-with-backslashes >a-string-with-slashes >a-string-with-slashes str1='twocubed' array=(the number of protons in an oxygen nucleus) print $#str1 ${#str1} "$#str1 ${#str1}" $#array ${#array} "$#array ${#array}" 0:${#...}, $#... >8 8 8 8 8 8 8 8 array=(once bitten twice shy) print IF${array}THEN print IF${^array}THEN 0:basic ${^...} >IFonce bitten twice shyTHEN >IFonceTHEN IFbittenTHEN IFtwiceTHEN IFshyTHEN # Quote ${array} here because {...,...} doesn't like unquoted spaces. print IF{"${array}",THEN}ELSE print IF{${^array},THEN}ELSE 0:combined ${^...} and {...,...} >IFonce bitten twice shyELSE IFTHENELSE >IFonceELSE IFTHENELSE IFbittenELSE IFTHENELSE IFtwiceELSE IFTHENELSE IFshyELSE IFTHENELSE str1='one word' print -l $str1 ${=str1} "split ${=str1}wise" 0:${=...} >one word >one >word >split one >wordwise str1='*' print $str1 ${~str1} $~str1 setopt globsubst print $str1 unsetopt globsubst 0:${~...} and globsubst >* boringfile evenmoreboringfile boringfile evenmoreboringfile >boringfile evenmoreboringfile # The following tests a bug where globsubst didn't preserve # backslashes when printing out the original string. str1='\\*\\' ( setopt globsubst nonomatch [[ \\\\ = $str1 ]] && print -r '\\ matched by' $str1 [[ \\foo\\ = $str1 ]] && print -r '\\foo matched by' $str1 [[ a\\b\\ = $str1 ]] || print -r 'a\\b not matched by' $str1 ) 0:globsubst with backslashes >\\ matched by \\*\\ >\\foo matched by \\*\\ >a\\b not matched by \\*\\ print -l "${$(print one word)}" "${=$(print two words)}" 0:splitting of $(...) inside ${...} >one word >two >words print -l "${(f)$(print first line\\nsecond line\\nthird line)}" 0:${(f)$(...)} >first line >second line >third line array1=( uno ) print -l ${(A)newarray=splitting by numbers} print -l ${(t)newarray} print -l ${(A)=newarray::=splitting by spaces, actually} print -l ${(t)newarray} print -l ${(A)newarray::=$array1} print -l ${(t)newarray} print -l ${newarray::=$array1} print -l ${(t)newarray} print -l ${newarray::=$array2} print -l ${(t)newarray} 0:${(A)...=...}, ${(A)...::=...}, ${scalar=$array} >splitting by numbers >array >splitting >by >spaces, >actually >array >uno >array >uno >scalar >the second array >scalar newarray=("split me" "split me" "I\'m yours") print -l "${(@)newarray}" 0:"${(@)...}" >split me >split me >I'm yours foo='$(print Howzat usay)' print -l ${(e)foo} 0:${(e)...} >Howzat >usay foo='`print Howzat usay`' print -l ${(e)foo} 0:Regress ${(e)...} with backticks (see zsh-workers/15871) >Howzat >usay foo='I'\''m nearly out of my mind with tedium' bar=foo print ${(P)bar} 0:${(P)...} >I'm nearly out of my mind with tedium foo=(I could be watching that programme I recorded) print ${(o)foo} print ${(oi)foo} print ${(O)foo} print ${(Oi)foo} 0:${(o)...}, ${(O)...} >I I be could programme recorded that watching >be could I I programme recorded that watching >watching that recorded programme could be I I >watching that recorded programme I I could be foo=(yOU KNOW, THE ONE WITH wILLIAM dALRYMPLE) bar=(doing that tour of India.) print ${(L)foo} print ${(U)bar} 0:${(L)...}, ${(U)...} >you know, the one with william dalrymple >DOING THAT TOUR OF INDIA. foo='instead here I am stuck by the computer' print ${(C)foo} 0:${(C)...} >Instead Here I Am Stuck By The Computer foo=$'\x7f\x00' print ${(V)foo} 0:${(V)...} >^?^@ foo='playing '\''stupid'\'' "games" \w\i\t\h $quoting.' print -r ${(q)foo} print -r ${(qq)foo} print -r ${(qqq)foo} print -r ${(qqqq)foo} 0:${(q...)...} >playing\ \'stupid\'\ \"games\"\ \\w\\i\\t\\h\ \$quoting. >'playing '\''stupid'\'' "games" \w\i\t\h $quoting.' >"playing 'stupid' \"games\" \\w\\i\\t\\h \$quoting." >$'playing \'stupid\' "games" \\w\\i\\t\\h $quoting.' foo="'and now' \"even the pubs\" \\a\\r\\e shut." print -r ${(Q)foo} 0:${(Q)...} >and now even the pubs are shut. foo="X$'\x41'$'\x42'Y" print -r ${(Q)foo} 0:${(Q)...} with handling of $'...' >XABY psvar=(dog) setopt promptsubst foo='It shouldn'\''t $(happen) to a %1v.' bar='But `echo what can you do\?`' print -r ${(%)foo} print -r ${(%%)bar} 0:${(%)...} >It shouldn't $(happen) to a dog. >But what can you do? foo='unmatched "' print ${(QX)foo} 1:${(QX)...} ?(eval):2: unmatched " array=(characters in an array) print ${(c)#array} 0:${(c)#...} >22 print ${(w)#array} str='colon::bolon::solon' print ${(ws.:.)#str} print ${(Ws.:.)#str} 0:${(w)...}, ${(W)...} >4 >3 >5 typeset -A assoc assoc=(key1 val1 key2 val2) print ${(o)assoc} print ${(ok)assoc} print ${(ov)assoc} print ${(okv)assoc} 0:${(k)...}, ${(v)...} >val1 val2 >key1 key2 >val1 val2 >key1 key2 val1 val2 word="obfuscatory" print !${(l.16.)word}! +${(r.16.)word}+ 0:simple padding >! obfuscatory! +obfuscatory + foo=(resulting words uproariously padded) print ${(pl.10..\x22..X.)foo} 0:${(pl...)...} >Xresulting """"Xwords roariously """Xpadded print ${(l.5..X.r.5..Y.)foo} print ${(l.6..X.r.4..Y.)foo} print ${(l.7..X.r.3..Y.)foo} print ${(l.6..X..A.r.6..Y..B.)foo} print ${(l.6..X..AROOGA.r.6..Y..BARSOOM.)foo} 0:simultaneous left and right padding >Xresulting XXXwordsYY proariousl XXpaddedYY >XXresultin XXXXwordsY uproarious XXXpaddedY >XXXresulti XXXXXwords Xuproariou XXXXpadded >XAresultingB XXXAwordsBYY uproariously XXApaddedBYY >GAresultingB OOGAwordsBAR uproariously OGApaddedBAR foo=(why in goodness name am I doing this) print ${(r.5..!..?.)foo} 0:${(r...)...} >why?! in?!! goodn name? am?!! I?!!! doing this? array=(I\'m simply putting a brave face on) print ${(j:--:)array} 0:${(j)...} >I'm--simply--putting--a--brave--face--on print ${(F)array} 0:${(F)...} >I'm >simply >putting >a >brave >face >on string='zometimez zis getz zplit on a z' print -l ${(s?z?)string} 0:${(s...)...} >ometime > >is get > >plit on a str=s arr=(a) typeset -A ass ass=(a a) integer i float f print ${(t)str} ${(t)arr} ${(t)ass} ${(t)i} ${(t)f} 0:${(t)...} >scalar array association-local integer-local float-local # it's not quite clear that these are actually right unless you know # the algorithm: search along the string for the point at which the # first (last) match occurs, for ## (%%), then take the shortest possible # version of that for # (%). it's as good a definition as anything. string='where is the white windmill, whispered walter wisely' print ${(S)string#h*e} print ${(S)string##h*e} print ${(S)string%h*e} print ${(S)string%%h*e} 0:${(S)...#...} etc. >wre is the white windmill, whispered walter wisely >wly >where is the white windmill, wred walter wisely >where is the white windmill, wly setopt extendedglob print ${(SI:1:)string##w[^[:space:]]# } print ${(SI:1+1:)string##w[^[:space:]]# } print ${(SI:1+1+1:)string##w[^[:space:]]# } print ${(SI:1+1+1+1:)string##w[^[:space:]]# } 0:${(I:...:)...} >is the white windmill, whispered walter wisely >where is the windmill, whispered walter wisely >where is the white whispered walter wisely >where is the white windmill, walter wisely print ${(MSI:1:)string##w[^[:space:]]# } 0:${(M...)...} >where print ${(R)string//w[a-z]# #} 0:${(R)...} >is the , # This (1) doesn't work with // or / # (2) perhaps ought to be 18, to be consistent with normal zsh # substring indexing and with backreferences. print ${(BES)string##white} 0:${(BE...)...} >14 19 print ${(NS)string##white} 0:${(N)...} >5 string='abcdefghijklmnopqrstuvwxyz' print ${${string%[aeiou]*}/(#m)?(#e)/${(U)MATCH}} 0:Rule 1: Nested substitutions >abcdefghijklmnopqrsT array=(et Swann avec cette muflerie intermittente) string="qui reparaissait chez lui" print ${array[4,5]} print ${array[4,5][1]} print ${array[4,5][1][2,3]} print ${string[4,5]} print ${string[4,5][1]} 0:Rule 2: Parameter subscripting >cette muflerie >cette >et > r > foo=stringalongamax print ${${(P)foo[1,6]}[1,3]} 0:Rule 3: Parameter Name Replacement >qui print "${array[5,6]}" print "${(j.:.)array[1,2]}" 0:Rule 4: Double-Quoted Joining >muflerie intermittente >et:Swann print "${${array}[5,7]}" print "${${(@)array}[1,2]}" 0:Rule 5: Nested Subscripting >wan >et Swann print "${${(@)array}[1,2]#?}" print "${(@)${(@)array}[1,2]#?}" 0:Rule 6: Modifiers >t Swann >t wann array=(she sells z shells by the z shore) (IFS='+'; print ${(s.s.)array}) 0:Rule 7: Forced Joining, and 8: Forced splitting >he+ ell +z+ hell +by+the+z+ hore setopt shwordsplit string='another poxy boring string' print -l ${${string}/o/ } unsetopt shwordsplit 0:Rule 9: Shell Word Splitting >an >ther >p >xy >b >ring >string setopt nonomatch foo='b* e*' print ${(e)~foo} print ${(e)~=foo} 0:Rule 10: Re-Evaluation >b* e* >boringfile evenmoreboringfile # ${bar} -> $bar here would yield "bad substitution". bar=confinement print ${(el.20..X.)${bar}} 0:Rule 11: Padding >XXXXXXXXXconfinement foo=(bar baz) bar=(ax1 bx1) print "${(@)${foo}[1]}" print "${${(@)foo}[1]}" print -l ${(s/x/)bar} print -l ${(j/x/s/x/)bar} print -l ${(s/x/)bar%%1*} 0:Examples in manual on parameter expansion >b >bar >a >1 b >1 >a >1 >b >1 >a > b set If "this test fails" "we have broken" the shell again print -l ${1+"$@"} 0:Regression test of ${1+"$@"} bug >If >this test fails >we have broken >the >shell >again set If "this test fails" "we have broken" the shell again print -l "${(A)foo::=$@}" print -l ${(t)foo} print -l $foo 0:Regression test of "${(A)foo=$@}" bug >If this test fails we have broken the shell again >array >If >this test fails >we have broken >the >shell >again local sure_that='sure that' varieties_of='varieties of' one=1 two=2 extra=(5 4 3) unset foo set Make $sure_that "this test keeps" on 'preserving all' "$varieties_of" quoted whitespace print -l ${=1+"$@"} print -l ${(A)=foo=Make $sure_that "this test keeps" on 'preserving all' "$varieties_of" quoted whitespace} print ${(t)foo} print -l ${=1+$one $two} print -l ${1+$extra$two$one} 0:Regression test of ${=1+"$@"} bug and some related expansions >Make >sure that >this test keeps >on >preserving all >varieties of >quoted >whitespace >Make >sure >that >this test keeps >on >preserving all >varieties of >quoted >whitespace >array >1 >2 >5 >4 >321 splitfn() { emulate -L sh local HOME="/differs from/bash" foo='1 2' bar='3 4' print -l ${1:-~} touch has\ space print -l ${1:-*[ ]*} print -l ${1:-*[\ ]*} print -l ${1:-*} print -l ${1:-"$foo" $bar} print -l ${==1:-$foo $bar} rm has\ space } splitfn 0:More bourne-shell-compatible nested word-splitting with wildcards and ~ >/differs from/bash >*[ >]* >has space >boringfile >evenmoreboringfile >has space >1 2 >3 >4 >1 2 3 4 splitfn() { local IFS=.- local foo=1-2.3-4 # print "Called with argument '$1'" print "No quotes" print -l ${=1:-1-2.3-4} ${=1:-$foo} print "With quotes on default argument only" print -l ${=1:-"1-2.3-4"} ${=1:-"$foo"} } print 'Using "="' splitfn splitfn 5.6-7.8 # splitfn() { emulate -L zsh setopt shwordsplit local IFS=.- local foo=1-2.3-4 # print "Called with argument '$1'" print "No quotes" print -l ${1:-1-2.3-4} ${1:-$foo} print "With quotes on default argument only" print -l ${1:-"1-2.3-4"} ${1:-"$foo"} } print Using shwordsplit splitfn splitfn 5.6-7.8 0:Test of nested word splitting with and without quotes >Using "=" >Called with argument '' >No quotes >1 >2 >3 >4 >1 >2 >3 >4 >With quotes on default argument only >1-2.3-4 >1-2.3-4 >Called with argument '5.6-7.8' >No quotes >5 >6 >7 >8 >5 >6 >7 >8 >With quotes on default argument only >5 >6 >7 >8 >5 >6 >7 >8 >Using shwordsplit >Called with argument '' >No quotes >1 >2 >3 >4 >1 >2 >3 >4 >With quotes on default argument only >1-2.3-4 >1-2.3-4 >Called with argument '5.6-7.8' >No quotes >5 >6 >7 >8 >5 >6 >7 >8 >With quotes on default argument only >5 >6 >7 >8 >5 >6 >7 >8 # Tests a long-standing bug with joining on metafied characters in IFS (array=(one two three) IFS=$'\0' foo="$array" for (( i = 1; i <= ${#foo}; i++ )); do char=${foo[i]} print $(( #char )) done) 0:Joining with NULL character from IFS >111 >110 >101 >0 >116 >119 >111 >0 >116 >104 >114 >101 >101 unset SHLVL (( SHLVL++ )) print $SHLVL 0:Unsetting and recreation of numerical special parameters >1 unset manpath print $+MANPATH manpath=(/here /there) print $MANPATH unset MANPATH print $+manpath MANPATH=/elsewhere:/somewhere print $manpath 0:Unsetting and recreation of tied special parameters >0 >/here:/there >0 >/elsewhere /somewhere local STRING=a:b typeset -T STRING string print $STRING $string unset STRING set -A string x y z print $STRING $string STRING=a:b typeset -T STRING string print $STRING $string unset STRING set -A string x y z print $STRING $string STRING=a:b typeset -T STRING string print $STRING $string unset string STRING=x:y:z print $STRING $string STRING=a:b typeset -T STRING string print $STRING $string unset string STRING=x:y:z print $STRING $string 0:Unsetting and recreation of tied normal parameters >a:b a b >x y z >a:b a b >x y z >a:b a b >x:y:z >a:b a b >x:y:z string='look for a match in here' if [[ ${string%%(#b)(match)*} = "look for a " ]]; then print $match[1] $mbegin[1] $mend[1] $string[$mbegin[1],$mend[1]] print $#match $#mbegin $#mend else print That didn\'t work. fi 0:Parameters associated with backreferences >match 12 16 match >1 1 1 string='and look for a MATCH in here' if [[ ${(S)string%%(#m)M*H} = "and look for a in here" ]]; then print $MATCH $MBEGIN $MEND $string[$MBEGIN,$MEND] print $#MATCH else print Oh, dear. Back to the drawing board. fi 0:Parameters associated with (#m) flag >MATCH 16 20 MATCH >5 string='this is a string' print ${string//(#m)s/$MATCH $MBEGIN $MEND} 0:(#m) flag with pure string >this 4 4 is 7 7 a s 11 11tring print ${${~:-*}//(#m)*/$MATCH=$MATCH} 0:(#m) flag with tokenized input >*=* print -l JAMES${(u)${=:-$(echo yes yes)}}JOYCE print -l JAMES${(u)${=:-$(echo yes yes she said yes i will yes)}}JOYCE 0:Bug with (u) flag reducing arrays to one element >JAMESyesJOYCE >JAMESyes >she >said >i >willJOYCE foo= print "${${foo}/?*/replacement}" 0:Quoted zero-length strings are handled properly > file=aleftkept print ${file//(#b)(*)left/${match/a/andsome}} print ${file//(#b)(*)left/${match//a/andsome}} 0:Substitutions where $match is itself substituted in the replacement >andsomekept >andsomekept file=/one/two/three/four print ${file:fh} print ${file:F.1.h} print ${file:F+2+h} print ${file:F(3)h} print ${file:F<4>h} print ${file:F{5}h} 0:Modifiers with repetition >/ >/one/two/three >/one/two >/one >/ >/ nully=($'a\0c' $'a\0b\0b' $'a\0b\0a' $'a\0b\0' $'a\0b' $'a\0' $'a') for string in ${(o)nully}; do for (( i = 1; i <= ${#string}; i++ )); do foo=$string[i] printf "%02x" $(( #foo )) done print done 0:Sorting arrays with embedded nulls >61 >6100 >610062 >61006200 >6100620061 >6100620062 >610063 array=(X) patterns=("*X*" "spong" "a[b") for pat in $patterns; do print A${array[(r)$pat]}B C${array[(I)$pat]}D done 0:Bad patterns should never match array elements >AXB C1D >AB C0D >AB C0D foo=(a6 a117 a17 b6 b117 b17) print ${(n)foo} print ${(On)foo} 0:Numeric sorting >a6 a17 a117 b6 b17 b117 >b117 b17 b6 a117 a17 a6 x=sprodj x[-10]=scrumf print $x 0:Out of range negative scalar subscripts >scrumfsprodj a=(some sunny day) a[-10]=(we\'ll meet again) print -l $a 0:Out of range negative array subscripts >we'll >meet >again >some >sunny >day foo="line:with::missing::fields:in:it" print -l ${(s.:.)foo} 0:Removal of empty fields in unquoted splitting >line >with >missing >fields >in >it foo="line:with::missing::fields:in:it" print -l "${(s.:.)foo}" 0:Hacky removal of empty fields in quoted splitting with no "@" >line >with >missing >fields >in >it foo="line:with::missing::fields:in:it" print -l "${(@s.:.)foo}" 0:Retention of empty fields in quoted splitting with "@" >line >with > >missing > >fields >in >it