mirror of
https://github.com/zdharma-continuum/zinit-module.git
synced 2024-11-21 13:27:58 +01:00
2058 lines
40 KiB
Text
2058 lines
40 KiB
Text
# Test parameter expansion. Phew.
|
|
# (By the way, did I say "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
|
|
|
|
x=()
|
|
print ${+x} ${+x[1]} ${+x[(r)foo]} ${+x[(r)bar]}
|
|
x=(foo)
|
|
print ${+x} ${+x[1]} ${+x[(r)foo]} ${+x[(r)bar]}
|
|
0:$+... with arrays
|
|
>1 0 0 0
|
|
>1 1 1 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
|
|
|
|
unset array
|
|
print ${#${(A)=array=word}}
|
|
0:${#${(A)=array=word}} counts array elements
|
|
>1
|
|
|
|
(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
|
|
|
|
PROMPT="" $ZTST_testdir/../Src/zsh -fis <<<'
|
|
unsetopt PROMPT_SP
|
|
PS1="" PS2="" PS3="" PS4="" RPS1="" RPS2=""
|
|
exec 2>&1
|
|
foo() {
|
|
print ${1:?no arguments given}
|
|
print not reached
|
|
}
|
|
foo
|
|
print reached
|
|
' 2>/dev/null
|
|
0:interactive shell returns to top level on ${...?...} error
|
|
*>*foo:1: 1: no arguments given
|
|
>reached
|
|
|
|
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
|
|
|
|
args=('one' '#foo' '(bar' "'three'" two)
|
|
mod=('#foo' '(bar' "'three'" sir_not_appearing_in_this_film)
|
|
print ${args:|mod}
|
|
print ${args:*mod}
|
|
print "${(@)args:|mod}"
|
|
print "${(@)args:*mod}"
|
|
args=(two words)
|
|
mod=('one word' 'two words')
|
|
print "${args:|mod}"
|
|
print "${args:*mod}"
|
|
scalar='two words'
|
|
print ${scalar:|mod}
|
|
print ${scalar:*mod}
|
|
print ${args:*nonexistent}
|
|
empty=
|
|
print ${args:*empty}
|
|
0:"|" array exclusion and "*" array intersection
|
|
>one two
|
|
>#foo (bar 'three'
|
|
>one two
|
|
>#foo (bar 'three'
|
|
>
|
|
>two words
|
|
>
|
|
>two words
|
|
>
|
|
>
|
|
|
|
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
|
|
|
|
set 1 2 3 4 5 6 7 8 9
|
|
print ${##}
|
|
set 1 2 3 4 5 6 7 8 9 10
|
|
print ${##}
|
|
print ${##""}
|
|
print ${##1}
|
|
print ${##2}
|
|
print ${###<->} # oh, for pete's sake...
|
|
0:${##} is length of $#, and other tales of hash horror
|
|
>1
|
|
>2
|
|
>10
|
|
>0
|
|
>10
|
|
>
|
|
|
|
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 \\*\\
|
|
|
|
(
|
|
setopt globsubst
|
|
foo="boring*"
|
|
print ${foo+$foo}
|
|
print ${foo+"$foo"}
|
|
print ${~foo+"$foo"}
|
|
)
|
|
0:globsubst together with nested quoted expansion
|
|
>boringfile
|
|
>boring*
|
|
>boringfile
|
|
|
|
print -l "${$(print one word)}" "${=$(print two words)}"
|
|
0:splitting of $(...) inside ${...}
|
|
>one word
|
|
>two
|
|
>words
|
|
|
|
(setopt shwordsplit # ensure this doesn't get set in main shell...
|
|
test_splitting ()
|
|
{
|
|
array="one two three"
|
|
for e in $array; do
|
|
echo "'$e'"
|
|
done
|
|
}
|
|
test_split_var=
|
|
echo _${test_split_var:=$(test_splitting)}_
|
|
echo "_${test_split_var}_")
|
|
0:SH_WORD_SPLIT inside $(...) inside ${...}
|
|
>_'one' 'two' 'three'_
|
|
>_'one'
|
|
>'two'
|
|
>'three'_
|
|
|
|
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='\u65\123'
|
|
print -r ${(g:o:)foo}
|
|
foo='\u65\0123^X\C-x'
|
|
print -r ${(g::)foo}
|
|
foo='^X'
|
|
bar='\C-\130'
|
|
[[ ${(g:c:)foo} == ${(g:oe:)bar} ]]
|
|
echo $?
|
|
0:${(g)...}
|
|
>eS
|
|
>eS^X\C-x
|
|
>0
|
|
|
|
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
|
|
#' deconfuse emacs
|
|
|
|
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 -r -- ${(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}
|
|
print -r ${(q-)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.'
|
|
>'playing '\'stupid\'' "games" \w\i\t\h $quoting.'
|
|
|
|
print -r ${(qqqq):-""}
|
|
0:workers/36551: literal empty string in ${(qqqq)...}
|
|
>$''
|
|
|
|
x=( a '' '\b' 'c d' '$e' )
|
|
print -r ${(q)x}
|
|
print -r ${(q-)x}
|
|
0:Another ${(q...)...} test
|
|
>a '' \\b c\ d \$e
|
|
>a '' '\b' 'c d' '$e'
|
|
|
|
print -r -- ${(q-):-foo}
|
|
print -r -- ${(q-):-foo bar}
|
|
print -r -- ${(q-):-"*(.)"}
|
|
print -r -- ${(q-):-"wow 'this is cool' or is it?"}
|
|
print -r -- ${(q-):-"no-it's-not"}
|
|
0:${(q-)...} minimal single quoting
|
|
>foo
|
|
>'foo bar'
|
|
>'*(.)'
|
|
>'wow '\''this is cool'\'' or is it?'
|
|
>no-it\'s-not
|
|
|
|
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
|
|
|
|
# The following may look a bit random.
|
|
# For the split we are checking that anything that
|
|
# would normally be followed by a different word has
|
|
# an argument break after it and anything that wouldn't doesn't.
|
|
# For the (Q) we are simply checking that nothing disappears
|
|
# in the parsing.
|
|
foo='<five> {six} (seven) >eight< }nine{ |forty-two| $many$ )ten( more'
|
|
array=(${(z)foo})
|
|
print -l ${(Q)array}
|
|
0:${(z)...} and ${(Q)...} for some hard to parse cases
|
|
><
|
|
>five
|
|
>>
|
|
>{six}
|
|
>(
|
|
>seven
|
|
>)
|
|
>>
|
|
>eight
|
|
><
|
|
>}nine{
|
|
>|
|
|
>forty-two
|
|
>|
|
|
>$many$
|
|
>)
|
|
>ten( more
|
|
|
|
strings=(
|
|
'foo=(1 2 3)'
|
|
'(( 3 + 1 == 8 / 2 ))'
|
|
'for (( i = 1 ; i < 10 ; i++ ))'
|
|
'((0.25542 * 60) - 15)*60'
|
|
'repeat 3 (x)'
|
|
'repeat 3 (echo foo; echo bar)'
|
|
'repeat $(( 2 + 4 )) (x)'
|
|
'repeat $( : foo bar; echo 4) (x)'
|
|
'repeat "1"'\''2'\''$(( 3 + 0 ))$((echo 4);)\ 5 (x)'
|
|
)
|
|
for string in $strings; do
|
|
array=(${(z)string})
|
|
for (( i = 1; i <= ${#array}; i++ )); do
|
|
print -r -- "${i}:${array[i]}:"
|
|
done
|
|
done
|
|
0:Some syntactical expressions that are hard to split into words with (z).
|
|
>1:foo=(:
|
|
>2:1:
|
|
>3:2:
|
|
>4:3:
|
|
>5:):
|
|
>1:(( 3 + 1 == 8 / 2 )):
|
|
>1:for:
|
|
>2:((:
|
|
# Leading whitespace is removed, because the word proper hasn't started;
|
|
# trailing whitespace is left because the word is terminated by the
|
|
# semicolon or double parentheses. Bit confusing but sort of consistent.
|
|
>3:i = 1 ;:
|
|
>4:i < 10 ;:
|
|
>5:i++ :
|
|
>6:)):
|
|
# This one needs resolving between a math expression and
|
|
# a command, which causes interesting effects internally.
|
|
>1:(:
|
|
>2:(:
|
|
>3:0.25542:
|
|
>4:*:
|
|
>5:60:
|
|
>6:):
|
|
>7:-:
|
|
>8:15:
|
|
>9:):
|
|
>10:*60:
|
|
>1:repeat:
|
|
>2:3:
|
|
>3:(:
|
|
>4:x:
|
|
>5:):
|
|
>1:repeat:
|
|
>2:3:
|
|
>3:(:
|
|
>4:echo:
|
|
>5:foo:
|
|
>6:;:
|
|
>7:echo:
|
|
>8:bar:
|
|
>9:):
|
|
>1:repeat:
|
|
>2:$(( 2 + 4 )):
|
|
>3:(:
|
|
>4:x:
|
|
>5:):
|
|
>1:repeat:
|
|
>2:$( : foo bar; echo 4):
|
|
>3:(:
|
|
>4:x:
|
|
>5:):
|
|
>1:repeat:
|
|
>2:"1"'2'$(( 3 + 0 ))$((echo 4);)\ 5:
|
|
>3:(:
|
|
>4:x:
|
|
>5:):
|
|
|
|
|
|
line=$'A line with # someone\'s comment\nanother line # (1 more\nanother one'
|
|
print "*** Normal ***"
|
|
print -l ${(z)line}
|
|
print "*** Kept ***"
|
|
print -l ${(Z+c+)line}
|
|
print "*** Removed ***"
|
|
print -l ${(Z+C+)line}
|
|
0:Comments with (z)
|
|
>*** Normal ***
|
|
>A
|
|
>line
|
|
>with
|
|
>#
|
|
>someone's comment
|
|
>another line # (1 more
|
|
>another one
|
|
>*** Kept ***
|
|
>A
|
|
>line
|
|
>with
|
|
># someone's comment
|
|
>;
|
|
>another
|
|
>line
|
|
># (1 more
|
|
>;
|
|
>another
|
|
>one
|
|
>*** Removed ***
|
|
>A
|
|
>line
|
|
>with
|
|
>;
|
|
>another
|
|
>line
|
|
>;
|
|
>another
|
|
>one
|
|
|
|
line='with comment # at the end'
|
|
print -l ${(Z+C+)line}
|
|
0:Test we don't get an additional newline token
|
|
>with
|
|
>comment
|
|
|
|
line=$'echo one\necho two # with a comment\necho three'
|
|
print -l ${(Z+nc+)line}
|
|
0:Treating zplit newlines as ordinary whitespace
|
|
>echo
|
|
>one
|
|
>echo
|
|
>two
|
|
># with a comment
|
|
>echo
|
|
>three
|
|
|
|
print -rl - ${(z):-":;(( echo 42 "}
|
|
0:${(z)} with incomplete math expressions
|
|
>:
|
|
>;
|
|
>(( echo 42
|
|
|
|
# From parse error on it's not possible to split.
|
|
# Just check we get the complete string.
|
|
foo='echo $(|||) bar'
|
|
print -rl ${(z)foo}
|
|
0:$($(z)} with parse error in command substitution.
|
|
>echo
|
|
>$(|||) bar
|
|
|
|
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 "
|
|
# " deconfuse emacs
|
|
|
|
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
|
|
#" deconfuse emacs
|
|
|
|
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}
|
|
setopt nomatch
|
|
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
|
|
|
|
typeset -T tied1 tied2 +
|
|
typeset -T tied2 tied1 +
|
|
1:Attempts to swap tied variables are safe but futile
|
|
?(eval):typeset:2: already tied as non-scalar: tied2
|
|
|
|
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
|
|
#' deconfuse emacs
|
|
|
|
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
|
|
|
|
print -l JAMES${(u)${=:-$(echo yes yes she said yes i will yes she said she will and yes she did yes)}}JOYCE
|
|
0:New hash seive unique algorithm for arrays of more than 10 elements
|
|
>JAMESyes
|
|
>she
|
|
>said
|
|
>i
|
|
>will
|
|
>and
|
|
>didJOYCE
|
|
|
|
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
|
|
>/
|
|
>/
|
|
|
|
baz=foo/bar
|
|
zab=oof+rab
|
|
print ${baz:s/\//+/}
|
|
print "${baz:s/\//+/}"
|
|
print ${zab:s/+/\//}
|
|
print "${zab:s/+/\//}"
|
|
0:Quoting of separator in substitution modifier
|
|
>foo+bar
|
|
>foo+bar
|
|
>oof/rab
|
|
>oof/rab
|
|
|
|
bsbs='X\\\\Y'
|
|
print -r -- ${bsbs:s/\\/\\/}
|
|
print -r -- "${bsbs:s/\\/\\/}"
|
|
print -r -- ${bsbs:s/\\\\/\\\\/}
|
|
print -r -- "${bsbs:s/\\\\/\\\\/}"
|
|
print -r -- ${bsbs:gs/\\/\\/}
|
|
print -r -- "${bsbs:gs/\\/\\/}"
|
|
print -r -- ${bsbs:gs/\\\\/\\\\/}
|
|
print -r -- "${bsbs:gs/\\\\/\\\\/}"
|
|
0:Handling of backslashed backslashes in substitution modifier
|
|
>X\\\\Y
|
|
>X\\\\Y
|
|
>X\\\\Y
|
|
>X\\\\Y
|
|
>X\\\\Y
|
|
>X\\\\Y
|
|
>X\\\\Y
|
|
>X\\\\Y
|
|
|
|
print -r ${${:-one/two}:s,/,X&Y,}
|
|
print -r ${${:-one/two}:s,/,X\&Y,}
|
|
print -r ${${:-one/two}:s,/,X\\&Y,}
|
|
print -r "${${:-one/two}:s,/,X&Y,}"
|
|
print -r "${${:-one/two}:s,/,X\&Y,}"
|
|
print -r "${${:-one/two}:s,/,X\\&Y,}"
|
|
0:Quoting of ampersand in substitution modifier RHS
|
|
>oneX/Ytwo
|
|
>oneX&Ytwo
|
|
>oneX\/Ytwo
|
|
>oneX/Ytwo
|
|
>oneX&Ytwo
|
|
>oneX\/Ytwo
|
|
|
|
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
|
|
|
|
# ' emacs likes this close quote
|
|
|
|
a=(sping spang spong bumble)
|
|
print ${a[(i)spong]}
|
|
print ${a[(i)spung]}
|
|
print ${a[(ib.1.)spong]}
|
|
print ${a[(ib.4.)spong]}
|
|
print ${a[(ib.10.)spong]}
|
|
0:In and out of range reverse matched indices without and with b: arrays
|
|
>3
|
|
>5
|
|
>3
|
|
>5
|
|
>5
|
|
|
|
a="thrimblewuddlefrong"
|
|
print ${a[(i)w]}
|
|
print ${a[(i)x]}
|
|
print ${a[(ib.3.)w]}
|
|
print ${a[(ib.10.)w]}
|
|
print ${a[(ib.30.)w]}
|
|
0:In and out of range reverse matched indices without and with b: strings
|
|
>9
|
|
>20
|
|
>9
|
|
>20
|
|
>20
|
|
|
|
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
|
|
>
|
|
|
|
str=abcd
|
|
print -l ${(s..)str}
|
|
print -l "${(s..)str}"
|
|
0:splitting of strings into characters
|
|
>a
|
|
>b
|
|
>c
|
|
>d
|
|
>a
|
|
>b
|
|
>c
|
|
>d
|
|
|
|
array=('%' '$' 'j' '*' '$foo')
|
|
print ${array[(i)*]} "${array[(i)*]}"
|
|
print ${array[(ie)*]} "${array[(ie)*]}"
|
|
key='$foo'
|
|
print ${array[(ie)$key]} "${array[(ie)$key]}"
|
|
key='*'
|
|
print ${array[(ie)$key]} "${array[(ie)$key]}"
|
|
0:Matching array indices with and without quoting
|
|
>1 1
|
|
>4 4
|
|
>5 5
|
|
>4 4
|
|
|
|
# Ordering of associative arrays is arbitrary, so we need to use
|
|
# patterns that only match one element.
|
|
typeset -A assoc_r
|
|
assoc_r=(star '*' of '*this*' and '!that!' or '(the|other)')
|
|
print ${(kv)assoc_r[(re)*]}
|
|
print ${(kv)assoc_r[(re)*this*]}
|
|
print ${(kv)assoc_r[(re)!that!]}
|
|
print ${(kv)assoc_r[(re)(the|other)]}
|
|
print ${(kv)assoc_r[(r)*at*]}
|
|
print ${(kv)assoc_r[(r)*(ywis|bliss|kiss|miss|this)*]}
|
|
print ${(kv)assoc_r[(r)(this|that|\(the\|other\))]}
|
|
0:Reverse subscripting associative arrays with literal matching
|
|
>star *
|
|
>of *this*
|
|
>and !that!
|
|
>or (the|other)
|
|
>and !that!
|
|
>of *this*
|
|
>or (the|other)
|
|
|
|
print $ZSH_SUBSHELL
|
|
(print $ZSH_SUBSHELL)
|
|
( (print $ZSH_SUBSHELL) )
|
|
( (print $ZSH_SUBSHELL); print $ZSH_SUBSHELL )
|
|
print $(print $ZSH_SUBSHELL)
|
|
cat =(print $ZSH_SUBSHELL)
|
|
0:ZSH_SUBSHELL
|
|
>0
|
|
>1
|
|
>2
|
|
>2
|
|
>1
|
|
>1
|
|
>1
|
|
|
|
foo=("|" "?")
|
|
[[ "|" = ${(j.|.)foo} ]] && print yes || print no
|
|
[[ "|" = ${(j.|.)~foo} ]] && print yes || print no
|
|
[[ "|" = ${(~j.|.)foo} ]] && print yes || print no
|
|
[[ "|" = ${(~~j.|.)foo} ]] && print yes || print no
|
|
[[ "|" = ${(j.|.~)foo} ]] && print yes || print no
|
|
[[ "x" = ${(j.|.)foo} ]] && print yes || print no
|
|
[[ "x" = ${(j.|.)~foo} ]] && print yes || print no
|
|
[[ "x" = ${(~j.|.)foo} ]] && print yes || print no
|
|
[[ "x" = ${(~~j.|.)foo} ]] && print yes || print no
|
|
[[ "x" = ${(j.|.~)foo} ]] && print yes || print no
|
|
0:GLOBSUBST only on parameter substitution arguments
|
|
>no
|
|
>yes
|
|
>yes
|
|
>no
|
|
>no
|
|
>no
|
|
>yes
|
|
>no
|
|
>no
|
|
>no
|
|
|
|
rcexbug() {
|
|
emulate -L zsh
|
|
setopt rcexpandparam
|
|
local -A hash
|
|
local -a full empty
|
|
full=(X x)
|
|
hash=(X x)
|
|
print ORDINARY ARRAYS
|
|
: The following behaves as documented in zshoptions
|
|
print FULL expand=$full
|
|
: Empty arrays remove the adjacent argument
|
|
print EMPTY expand=$empty
|
|
print ASSOCIATIVE ARRAY
|
|
print Subscript flags returning many values
|
|
print FOUND key=$hash[(I)X] val=$hash[(R)x]
|
|
: This should behave like $empty, and does
|
|
print LOST key=$hash[(I)y] val=$hash[(R)Y]
|
|
print Subscript flags returning single values
|
|
: Doc says "substitutes ... empty string"
|
|
: so must not behave like an empty array
|
|
print STRING key=$hash[(i)y] val=$hash[(r)Y]
|
|
}
|
|
rcexbug
|
|
0:Lookup failures on elements of arrays with RC_EXPAND_PARAM
|
|
>ORDINARY ARRAYS
|
|
>FULL expand=X expand=x
|
|
>EMPTY
|
|
>ASSOCIATIVE ARRAY
|
|
>Subscript flags returning many values
|
|
>FOUND key=X val=x
|
|
>LOST
|
|
>Subscript flags returning single values
|
|
>STRING key= val=
|
|
|
|
print $zsh_eval_context[1]
|
|
[[ $ZSH_EVAL_CONTEXT = ${(j.:.)zsh_eval_context} ]] || print Not equal!
|
|
(( icontext = ${#zsh_eval_context} + 1 ))
|
|
contextfn() { print $(print $zsh_eval_context[icontext,-1]); }
|
|
contextfn
|
|
0:$ZSH_EVAL_CONTEXT and $zsh_eval_context
|
|
>toplevel
|
|
>shfunc cmdsubst
|
|
|
|
foo="123456789"
|
|
print ${foo:3}
|
|
print ${foo: 1 + 3}
|
|
print ${foo:$(( 2 + 3))}
|
|
print ${foo:$(echo 3 + 3)}
|
|
print ${foo:3:1}
|
|
print ${foo: 1 + 3:(4-2)/2}
|
|
print ${foo:$(( 2 + 3)):$(( 7 - 6 ))}
|
|
print ${foo:$(echo 3 + 3):`echo 4 - 3`}
|
|
print ${foo: -1}
|
|
print ${foo: -10}
|
|
print ${foo:5:-2}
|
|
0:Bash-style offsets, scalar
|
|
>456789
|
|
>56789
|
|
>6789
|
|
>789
|
|
>4
|
|
>5
|
|
>6
|
|
>7
|
|
>9
|
|
>123456789
|
|
>67
|
|
|
|
foo=(1 2 3 4 5 6 7 8 9)
|
|
print ${foo:3}
|
|
print ${foo: 1 + 3}
|
|
print ${foo:$(( 2 + 3))}
|
|
print ${foo:$(echo 3 + 3)}
|
|
print ${foo:3:1}
|
|
print ${foo: 1 + 3:(4-2)/2}
|
|
print ${foo:$(( 2 + 3)):$(( 7 - 6 ))}
|
|
print ${foo:$(echo 3 + 3):`echo 4 - 3`}
|
|
print ${foo: -1}
|
|
print ${foo: -10}
|
|
print ${foo:5:-2}
|
|
0:Bash-style offsets, array
|
|
>4 5 6 7 8 9
|
|
>5 6 7 8 9
|
|
>6 7 8 9
|
|
>7 8 9
|
|
>4
|
|
>5
|
|
>6
|
|
>7
|
|
>9
|
|
>1 2 3 4 5 6 7 8 9
|
|
>6 7
|
|
|
|
testfn() {
|
|
emulate -L sh
|
|
set -A foo 1 2 3
|
|
set -- 1 2 3
|
|
str=abc
|
|
echo ${foo[*]:0:1}
|
|
echo ${foo[*]:1:1}
|
|
echo ${foo[*]: -1:1}
|
|
:
|
|
echo ${*:0:1}
|
|
echo ${*:1:1}
|
|
echo ${*: -1:1}
|
|
:
|
|
echo ${str:0:1}
|
|
echo ${str:1:1}
|
|
echo ${str: -1:1}
|
|
}
|
|
testfn
|
|
0:Bash-style offsets, Bourne-style indexing
|
|
>1
|
|
>2
|
|
>3
|
|
>testfn
|
|
>1
|
|
>3
|
|
>a
|
|
>b
|
|
>c
|
|
|
|
printf "%n" '[0]'
|
|
1:Regression test for identifier test
|
|
?(eval):1: not an identifier: [0]
|
|
|
|
str=rts
|
|
print ${str:0:}
|
|
1:Regression test for missing length after offset
|
|
?(eval):2: unrecognized modifier
|
|
|
|
foo="123456789"
|
|
print ${foo:5:-6}
|
|
1:Regression test for total length < 0 in string
|
|
?(eval):2: substring expression: 3 < 5
|
|
|
|
foo=(1 2 3 4 5 6 7 8 9)
|
|
print ${foo:5:-6}
|
|
1:Regression test for total length < 0 in array
|
|
?(eval):2: substring expression: 3 < 5
|
|
|
|
foo=(${(0)"$(print -n)"})
|
|
print ${#foo}
|
|
0:Nularg removed from split empty string
|
|
>0
|
|
|
|
(set -- a b c
|
|
setopt shwordsplit
|
|
IFS=
|
|
print -rl "$*"
|
|
unset IFS
|
|
print -rl "$*")
|
|
0:Regression test for shwordsplit with null or unset IFS and quoted array
|
|
>abc
|
|
>a b c
|
|
|
|
foo=
|
|
print ${foo:wq}
|
|
print ${:wq}
|
|
0:Empty parameter should not cause modifiers to crash the shell
|
|
>
|
|
>
|
|
|
|
# This used to cause uncontrolled behaviour, but at best
|
|
# you got the wrong output so the check is worth it.
|
|
args() { print $#; }
|
|
args ${:*}
|
|
args ${:|}
|
|
0:Intersection and disjunction with empty parameters
|
|
>0
|
|
>0
|
|
|
|
foo=(a b c)
|
|
bar=(1 2 3)
|
|
print ${foo:^bar}
|
|
print ${foo:^^bar}
|
|
foo=(a b c d)
|
|
bar=(1 2)
|
|
print ${foo:^bar}
|
|
print ${foo:^^bar}
|
|
foo=('a a' b)
|
|
bar=(1 '2 2')
|
|
print -l "${foo:^bar}"
|
|
print -l "${(@)foo:^bar}"
|
|
0:Zipping arrays, correct output
|
|
>a 1 b 2 c 3
|
|
>a 1 b 2 c 3
|
|
>a 1 b 2
|
|
>a 1 b 2 c 1 d 2
|
|
# maybe this should be changed to output "a a b 1"
|
|
>a a b
|
|
>1
|
|
>a a
|
|
>1
|
|
>b
|
|
>2 2
|
|
|
|
foo=(a b c)
|
|
bar=()
|
|
print ${foo:^bar}
|
|
print ${foo:^^bar}
|
|
print ${bar:^foo}
|
|
print ${bar:^^foo}
|
|
print ${bar:^bar}
|
|
print ${bar:^^bar}
|
|
0:Zipping arrays, one or both inputs empty
|
|
>
|
|
>a b c
|
|
>
|
|
>a b c
|
|
>
|
|
>
|
|
|
|
foo=text
|
|
bar=()
|
|
print ${foo:^bar}
|
|
print ${bar:^^foo}
|
|
bar=other
|
|
print ${foo:^bar}
|
|
bar=(array elements)
|
|
print ${foo:^bar}
|
|
print ${foo:^^bar}
|
|
print ${bar:^foo}
|
|
print ${bar:^^foo}
|
|
0:Zipping arrays, scalar input
|
|
>
|
|
>text
|
|
>text other
|
|
>text array
|
|
>text array text elements
|
|
>array text
|
|
>array text elements text
|
|
|
|
foo=(a b c)
|
|
print ${foo:^^^bar}
|
|
1:Zipping arrays, parsing
|
|
?(eval):2: not an identifier: ^bar
|
|
|
|
(setopt nounset
|
|
print ${foo:^noexist})
|
|
1:Zipping arrays, NO_UNSET part 1
|
|
?(eval):2: noexist: parameter not set
|
|
|
|
(setopt nounset
|
|
print ${noexist:^foo})
|
|
1:Zipping arrays, NO_UNSET part 2
|
|
?(eval):2: noexist: parameter not set
|
|
|
|
expr="a@b,c@d:e@f,g@h:i@j,k@l"
|
|
for sep in : , @; do
|
|
print -l ${(ps.$sep.)expr}
|
|
done
|
|
0:Use of variable to get separator when splitting parameter
|
|
>a@b,c@d
|
|
>e@f,g@h
|
|
>i@j,k@l
|
|
>a@b
|
|
>c@d:e@f
|
|
>g@h:i@j
|
|
>k@l
|
|
>a
|
|
>b,c
|
|
>d:e
|
|
>f,g
|
|
>h:i
|
|
>j,k
|
|
>l
|
|
|
|
SHLVL=1
|
|
$ZTST_testdir/../Src/zsh -fc 'echo $SHLVL'
|
|
$ZTST_testdir/../Src/zsh -fc '(echo $SHLVL)'
|
|
0:SHLVL appears sensible when about to exit shell
|
|
>2
|
|
>2
|
|
|
|
# SHLVL is incremented twice and decremented once in between.
|
|
SHLVL=1
|
|
$ZTST_testdir/../Src/zsh -fc $ZTST_testdir/../Src/zsh' -fc "echo \$SHLVL"'
|
|
$ZTST_testdir/../Src/zsh -fc '('$ZTST_testdir/../Src/zsh' -fc "echo \$SHLVL")'
|
|
$ZTST_testdir/../Src/zsh -fc '( ('$ZTST_testdir/../Src/zsh' -fc "echo \$SHLVL"))'
|
|
0:SHLVL decremented upon implicit exec optimisation
|
|
>2
|
|
>2
|
|
>2
|
|
|
|
# SHLVL is incremented twice with no decrement in between.
|
|
SHLVL=1
|
|
$ZTST_testdir/../Src/zsh -fc '('$ZTST_testdir/../Src/zsh' -fc "echo \$SHLVL"); exit'
|
|
$ZTST_testdir/../Src/zsh -fc '(exec '$ZTST_testdir/../Src/zsh' -fc "echo \$SHLVL"); exit'
|
|
$ZTST_testdir/../Src/zsh -fc '( ('$ZTST_testdir/../Src/zsh' -fc "echo \$SHLVL"); exit)'
|
|
0:SHLVL not decremented upon exec in subshells
|
|
>3
|
|
>3
|
|
>3
|
|
|
|
# The following tests the return behaviour of parsestr/parsestrnoerr
|
|
alias param-test-alias='print $'\''\x45xpanded in substitution'\'
|
|
param='$(param-test-alias)'
|
|
print ${(e)param}
|
|
0:Alias expansion in command substitution in parameter evaluation
|
|
>Expanded in substitution
|
|
|
|
a=1 b=2 c=3
|
|
: One;
|
|
function {
|
|
: Two
|
|
echo $_
|
|
print -l $argv
|
|
} $_ Three
|
|
print -l $_ Four;
|
|
0:$_ with anonymous function
|
|
>Two
|
|
>One
|
|
>Three
|
|
>Three
|
|
>Four
|
|
|
|
a=1 b=2 c=3
|
|
: One
|
|
function {
|
|
: Two
|
|
echo $_
|
|
print -l $argv
|
|
}
|
|
print -l "$_" Four
|
|
0:$_ with anonymous function without arguments
|
|
>Two
|
|
>
|
|
>
|
|
>Four
|
|
|
|
funnychars='The qu*nk br!wan f@x j/mps o[]r \(e la~# ^"&;'
|
|
[[ $funnychars = ${~${(b)funnychars}} ]]
|
|
0:${(b)...} quoting protects from GLOB_SUBST
|
|
|
|
set -- foo
|
|
echo $(( $#*3 ))
|
|
emulate sh -c 'nolenwithoutbrace() { echo $#-1; }'
|
|
nolenwithoutbrace
|
|
0:Avoid confusion after overloaded characters in braceless substitution in sh
|
|
>13
|
|
>0-1
|
|
|
|
a="aaa bab cac"
|
|
b=d
|
|
echo $a:gs/a/${b}/
|
|
a=(aaa bab cac)
|
|
echo $a:gs/a/${b}/
|
|
0:History modifier works the same for scalar and array substitution
|
|
>ddd bdb cdc
|
|
>ddd bdb cdc
|
|
|
|
a=1_2_3_4_5_6
|
|
print ${a#(*_)(#c2)}
|
|
print ${a#(*_)(#c5)}
|
|
print ${a#(*_)(#c7)}
|
|
0:Complicated backtracking with match counts
|
|
>3_4_5_6
|
|
>6
|
|
>1_2_3_4_5_6
|
|
|
|
(setopt shwordsplit
|
|
do_test() {
|
|
print $#: "$@"
|
|
}
|
|
foo=bar
|
|
foo2="bar bar"
|
|
do_test ${:- foo }
|
|
do_test ${:- foo bar }
|
|
do_test ${:- $foo }
|
|
do_test ${:- $foo2 }
|
|
do_test x${:- foo }y
|
|
do_test x${:- foo bar }y
|
|
do_test x${:- $foo }y
|
|
do_test x${:- $foo2 }y
|
|
do_test x${foo:+ $foo }y
|
|
)
|
|
0:We Love SH_WORD_SPLIT Day celebrated with space at start of internal subst
|
|
>1: foo
|
|
>2: foo bar
|
|
>1: bar
|
|
>2: bar bar
|
|
>3: x foo y
|
|
>4: x foo bar y
|
|
>3: x bar y
|
|
>4: x bar bar y
|
|
>3: x bar y
|
|
|
|
(unsetopt shwordsplit # default, for clarity
|
|
do_test() {
|
|
print $#: "$@"
|
|
}
|
|
foo=bar
|
|
foo2="bar bar"
|
|
do_test ${:- foo }
|
|
do_test ${:- foo bar }
|
|
do_test ${:- $foo }
|
|
do_test ${:- $foo2 }
|
|
do_test x${:- foo }y
|
|
do_test x${:- foo bar }y
|
|
do_test x${:- $foo }y
|
|
do_test x${:- $foo2 }y
|
|
do_test x${foo:+ $foo }y
|
|
)
|
|
0:We Love NO_SH_WORD_SPLIT Even More Day celebrated as sanity check
|
|
>1: foo
|
|
>1: foo bar
|
|
>1: bar
|
|
>1: bar bar
|
|
>1: x foo y
|
|
>1: x foo bar y
|
|
>1: x bar y
|
|
>1: x bar bar y
|
|
>1: x bar y
|
|
|
|
testfn() {
|
|
local scalar=obfuscation
|
|
local -a array=(alpha bravo charlie delta echo foxtrot)
|
|
local -A assoc=(one eins two zwei three drei four vier)
|
|
local name subscript
|
|
for name subscript in scalar 3 array 5 assoc three; do
|
|
print ${${(P)name}[$subscript]}
|
|
done
|
|
}
|
|
testfn
|
|
0:${(P)...} with normal subscripting
|
|
>f
|
|
>echo
|
|
>drei
|
|
|
|
testfn() {
|
|
local s1=foo s2=bar
|
|
local -a val=(s1)
|
|
print ${${(P)val}[1,3]}
|
|
val=(s1 s2)
|
|
print ${${(P)val}[1,3]}
|
|
}
|
|
testfn
|
|
1:${(P)...} with array as name
|
|
>foo
|
|
?testfn:5: parameter name reference used with array
|
|
|
|
testfn() {
|
|
local -A assoc=(one buckle two show three knock four door)
|
|
local name='assoc[two]'
|
|
print ${${(P)name}[2,3]}
|
|
}
|
|
testfn
|
|
0:${(P)...} with internal subscripting
|
|
>ho
|
|
|
|
testfn() {
|
|
local one=two
|
|
local two=three
|
|
local three=four
|
|
local -a four=(all these worlds belong to foo)
|
|
print ${(P)${(P)${(P)one}}}
|
|
print ${${(P)${(P)${(P)one}}}[3]}
|
|
}
|
|
testfn
|
|
0:nested parameter name references
|
|
>all these worlds belong to foo
|
|
>worlds
|
|
|
|
(
|
|
path=(/random /value)
|
|
testfn1() {
|
|
local path=
|
|
print $#path
|
|
}
|
|
testfn1
|
|
testfn2() {
|
|
local path=/somewhere
|
|
print $#path $path
|
|
}
|
|
testfn2
|
|
print $#path $path
|
|
)
|
|
0:Local special variables with loose typing
|
|
>0
|
|
>1 /somewhere
|
|
>2 /random /value
|
|
|
|
print -r -- ${(q+):-}
|
|
print -r -- ${(q+)IFS}
|
|
print -r -- ${(q+):-oneword}
|
|
print -r -- ${(q+):-two words}
|
|
print -r -- ${(q+):-three so-called \'words\'}
|
|
(setopt rcquotes; print -r -- ${(q+):-three so-called \'words\'})
|
|
0:${(q+)...}
|
|
>''
|
|
>$' \t\n\C-@'
|
|
>oneword
|
|
>'two words'
|
|
>'three so-called '\''words'\'
|
|
>'three so-called ''words'''
|
|
|
|
array=(one two three)
|
|
array[1]=${nonexistent:-foo}
|
|
print $array
|
|
0:"-" works after "[" in same expression (Dash problem)
|
|
>foo two three
|
|
|
|
(
|
|
setopt shwordsplit
|
|
set -- whim:wham:whom
|
|
IFS=:
|
|
print -l $@
|
|
)
|
|
0:Splitting of $@ on IFS: single element
|
|
>whim
|
|
>wham
|
|
>whom
|
|
|
|
(
|
|
setopt shwordsplit
|
|
set -- one:two bucklemy:shoe
|
|
IFS=:
|
|
print -l $@
|
|
)
|
|
0:Splitting of $@ on IFS: multiple elements
|
|
# No forced joining in this case
|
|
>one
|
|
>two
|
|
>bucklemy
|
|
>shoe
|
|
|
|
(
|
|
set -- one:two bucklemy:shoe
|
|
print -l ${(s.:.)@}
|
|
)
|
|
0:Splitting of $@ on (s): multiple elements
|
|
# Forced joining in this case
|
|
>one
|
|
>two bucklemy
|
|
>shoe
|
|
|
|
(
|
|
set -- one:two bucklemy:shoe
|
|
print -l ${(@s.:.)@}
|
|
)
|
|
0:Splitting of $@ on (@s): multiple elements
|
|
# Forced non-joining in this case
|
|
>one
|
|
>two
|
|
>bucklemy
|
|
>shoe
|
|
|
|
(
|
|
set -- one:two bucklemy:shoe
|
|
IFS=
|
|
setopt shwordsplit
|
|
print -l ${@} ${(s.:.)*} ${(s.:.j.-.)*}
|
|
)
|
|
0:Joining of $@ does not happen when IFS is empty, but splitting $* does
|
|
>one:two
|
|
>bucklemy:shoe
|
|
>one
|
|
>twobucklemy
|
|
>shoe
|
|
>one
|
|
>two-bucklemy
|
|
>shoe
|
|
|
|
(
|
|
set -- "one two" "bucklemy shoe"
|
|
IFS=
|
|
setopt shwordsplit rcexpandparam
|
|
print -l "X${(@j.-.)*}"
|
|
)
|
|
0:Use of @ does not prevent forced join with j
|
|
>Xone two-bucklemy shoe
|
|
|
|
() { print -r -- "${(q)1}" "${(b)1}" "${(qq)1}" } '=foo'
|
|
0:(q) and (b) quoting deal with the EQUALS option
|
|
>\=foo =foo '=foo'
|
|
|
|
args() { print $#; }
|
|
a=(foo)
|
|
args "${a[3,-1]}"
|
|
args "${(@)a[3,-1]}"
|
|
0:Out-of-range multiple array subscripts with quoting, with and without (@)
|
|
>1
|
|
>0
|
|
|
|
a='~-/'; echo $~a
|
|
0:Regression: "-" became Dash in workers/37689, breaking ~- expansion
|
|
*>*
|
|
F:We do not care what $OLDPWD is, as long as it doesn't cause an error
|