# Test various shell options. # Interactive options not tested here: # ALWAYS_LAST_PROMPT # ALWAYS_TO_END # APPEND_HISTORY (history not maintained) # AUTO_LIST # AUTO_MENU # AUTO_NAME_DIRS (named directory table not maintained) # AUTO_PARAM_KEYS # AUTO_PARAM_SLASH # AUTO_REMOVE_SLASH # AUTO_RESUME # BANG_HIST # BASH_AUTO_LIST # BEEP (!) # BG_NICE # CHECK_JOBS # COMPLETE_ALIASES # COMPLETE_IN_WORD # CORRECT # CORRECT_ALL # CSH_JUNKIE_HISTORY # DVORAK # EXTENDED_HISTORY # FLOW_CONTROL # GLOB_COMPLETE # HIST_ALLOW_CLOBBER # HIST_BEEP # HIST_EXPIRE_DUPS_FIRST # HIST_FIND_NO_DUPS # HIST_IGNORE_ALL_DUPS # HIST_IGNORE_DUPS (-h) # HIST_IGNORE_SPACE (-g) # HIST_NO_FUNCTIONS # HIST_NO_STORE # HIST_REDUCE_BLANKS # HIST_SAVE_NO_DUPS # HIST_VERIFY # HUP # IGNORE_EOF # INC_APPEND_HISTORY # INTERACTIVE # INTERACTIVE_COMMENTS # LIST_AMBIGUOUS # LIST_BEEP # LIST_PACKED # LIST_ROWS_FIRST # LIST_TYPES # LOGIN # LONG_LIST_JOBS # MAIL_WARNING # MENU_COMPLETE # MONITOR # NOTIFY # OVERSTRIKE # PRINT_EIGHT_BIT # PROMPT_CR # PUSHD_SILENT # REC_EXACT # RM_STAR_SILENT # RM_STAR_WAIT # SHARE_HISTORY # SINGLE_LINE_ZLE # SUN_KEYBOARD_HACK # ZLE # The following require SHINSTDIN and are not (yet) tested: # AUTO_CD # SHINSTDIN # # Other difficult things I haven't done: # GLOBAL_RCS (uses fixed files outside build area) # HASH_CMDS ) # HASH_DIRS ) fairly seriously internal, hard to test at all # HASH_LIST_ALL ) # PRINT_EXIT_STATUS haven't worked out what this does yet, although # Bart suggested a fix. # PRIVILEGED (similar to GLOBAL_RCS) # RCS ( " " " " ) # SH_OPTION_LETTERS even I found this too dull to set up a test for # SINGLE_COMMAND kills shell # VERBOSE hard because done on input (c.f. SHINSTDIN). %prep mkdir options.tmp && cd options.tmp mkdir tmpcd touch tmpfile1 tmpfile2 mydir=$PWD mydirt=`print -P %~` catpath=$(which cat) lspath==ls %test alias echo='print foo' unsetopt aliases # use eval else aliases are all parsed at start eval echo bar setopt aliases eval echo bar unalias echo 0:ALIASES option >bar >foo bar setopt allexport testpm1=exported unsetopt allexport testpm2=unexported print ${(t)testpm1} print ${(t)testpm2} 0:ALL_EXPORT option >scalar-export >scalar # Count the number of directories on the stack. Don't care what they are. dircount() { dirs -v | tail -1 | awk '{ print $1 + 1}'; } unsetopt autopushd cd tmpcd dircount cd .. setopt autopushd cd tmpcd dircount unsetopt autopushd popd >/dev/null 0:AUTO_PUSHD option >1 >2 unsetopt badpattern print [a setopt badpattern print [b 1:BAD_PATTERN option >[a ?ZTST_execchunk:2: bad pattern: [b unsetopt bareglobqual nomatch print *(.) setopt bareglobqual nomatch print *(.) 0:BARE_GLOB_QUAL option >*(.) >tmpfile1 tmpfile2 setopt braceccl print {abcd} unsetopt braceccl print {abcd} 0:BRACE_CCL option >a b c d >{abcd} setopt bsdecho echo "histon\nimpington" echo -e "girton\ncottenham" unsetopt bsdecho echo "newnham\ncomberton" 0:BSD_ECHO option >histon\nimpington >girton >cottenham >newnham >comberton unsetopt c_bases print $(( [#16]15 )) print $(( [#8]9 )) setopt c_bases print $(( [#16]31 )) print $(( [#8]17 )) setopt octal_zeroes print $(( [#8]19 )) unsetopt c_bases octal_zeroes 0:C_BASES option >16#F >8#11 >0x1F >8#21 >023 setopt cdablevars # only absolute paths are eligible for ~-expansion cdablevar1=tmpcd (cd cdablevar1) cdablevar2=$PWD/tmpcd cd cdablevar2 cd .. print back in ${PWD:t} unsetopt cdablevars cd cdablevar2 1q:CDABLE_VARS option >back in options.tmp ?ZTST_execchunk:cd:2: no such file or directory: cdablevar1 ?ZTST_execchunk:cd:2: no such file or directory: cdablevar2 # CHASE_DOTS should go with CHASE_LINKS in B01cd.ztst # which saves me having to write it here. setopt noclobber rm -f foo1 bar1 rod1 echo waterbeach >foo1 (echo landbeach >foo1) cat foo1 (echo lode >>bar1) [[ -f bar1 ]] && print That shouldn\'t be there. echo denny >rod1 echo wicken >>rod1 cat rod1 unsetopt noclobber rm -f foo2 bar2 rod2 echo ely >foo2 echo march >foo2 cat foo2 echo wimpole >>bar2 cat bar2 echo royston >rod2 echo foxton >>rod2 cat rod2 rm -f foo* bar* rod* 0:CLOBBER option >waterbeach >denny >wicken >march >wimpole >royston >foxton ?ZTST_execchunk:2: file exists: foo1 ?ZTST_execchunk:2: no such file or directory: bar1 setopt cshjunkieloops eval 'for f in swaffham bulbeck; print $f; end' print next one should fail >&2 unsetopt cshjunkieloops eval 'for f in chesterton arbury; print $f; end' 1:CSH_JUNKIE_LOOPS option (for loop) >swaffham >bulbeck ?next one should fail ?ZTST_execchunk:-1: parse error near `end' setopt cshjunkiequotes print this should cause an error >&2 eval "print 'line one line two'" print this should not >&2 eval "print 'line three\\ line four'" unsetopt cshjunkiequotes 0:CSH_JUNKIE_QUOTES option >line three > line four ?this should cause an error ?ZTST_execchunk:-1: unmatched ' ?this should not nullcmd() { print '$NULLCMD run'; } readnullcmd() { print 'Running $READNULLCMD'; cat; } NULLCMD=nullcmd READNULLCMD=readnullcmd setopt cshnullcmd rm -f foo print "This should fail" >&2 (>foo) print "This should succeed" >&2 print "These are the contents of foo" >foo cat foo print "This should also fail" >&2 (foo These are the contents of foo >Running $READNULLCMD >$NULLCMD run ?This should fail ?ZTST_execchunk:2: redirection with no command ?This should succeed ?This should also fail ?ZTST_execchunk:2: redirection with no command # nomatch should be overridden by cshnullglob setopt nomatch cshnullglob print tmp* nothing* blah print -n 'hoping for no match: ' >&2 (print nothing* blah) print >&2 unsetopt cshnullglob nomatch print tmp* nothing* blah print nothing* blah 0:CSH_NULL_GLOB option >tmpcd tmpfile1 tmpfile2 blah >tmpcd tmpfile1 tmpfile2 nothing* blah >nothing* blah ?hoping for no match: ZTST_execchunk:2: no match ? # The trick is to avoid =cat being expanded in the output while $catpath is. setopt NO_equals print -n trick; print =cat setopt equals print -n trick; print =cat 0q:EQUALS option >trick=cat >trick$catpath # explanation of expected TRAPZERR output: from false and from # testfn() with ERR_EXIT on (hmm, should we really get a second one from # the function exiting?), then from the false only with ERR_EXIT off. TRAPZERR() { print ZERR trapped; } testfn() { setopt localoptions $2; print $1 before; false; print $1 after; } (testfn on errexit) testfn off unfunction TRAPZERR testfn 0:ERR_EXIT option >on before >ZERR trapped >ZERR trapped >off before >ZERR trapped >off after (print before; setopt noexec; print after) 0:NO_EXEC option >before # The EXTENDED_GLOB test doesn't test globbing fully --- it just tests # that certain patterns are treated literally with the option off # and as patterns with the option on. testfn() { print -n "$1 $2 $3 "; if [[ $1 = ${~2} ]]; then print yes; else print no; fi; } tests=('a#' '?~b' '^aa') strings=('a' 'aa' 'b' 'a#' '?~b' '^aa') for opt in noextendedglob extendedglob; do setopt $opt for test in $tests; do for string in $strings; do testfn $string $test $opt done done done 0:EXTENDED_GLOB option >a a# noextendedglob no >aa a# noextendedglob no >b a# noextendedglob no >a# a# noextendedglob yes >?~b a# noextendedglob no >^aa a# noextendedglob no >a ?~b noextendedglob no >aa ?~b noextendedglob no >b ?~b noextendedglob no >a# ?~b noextendedglob no >?~b ?~b noextendedglob yes >^aa ?~b noextendedglob no >a ^aa noextendedglob no >aa ^aa noextendedglob no >b ^aa noextendedglob no >a# ^aa noextendedglob no >?~b ^aa noextendedglob no >^aa ^aa noextendedglob yes >a a# extendedglob yes >aa a# extendedglob yes >b a# extendedglob no >a# a# extendedglob no >?~b a# extendedglob no >^aa a# extendedglob no >a ?~b extendedglob yes >aa ?~b extendedglob no >b ?~b extendedglob no >a# ?~b extendedglob no >?~b ?~b extendedglob no >^aa ?~b extendedglob no >a ^aa extendedglob yes >aa ^aa extendedglob no >b ^aa extendedglob yes >a# ^aa extendedglob yes >?~b ^aa extendedglob yes >^aa ^aa extendedglob yes foo() { print My name is $0; } unsetopt functionargzero foo setopt functionargzero foo unfunction foo 0:FUNCTION_ARGZERO option >My name is ZTST_execchunk >My name is foo setopt _NO_glob_ print tmp* set -o glob print tmp* 0:GLOB option >tmp* >tmpcd tmpfile1 tmpfile2 showit() { local v; for v in first second third; do eval print \$$v \$\{\(t\)$v\} done; } setit() { typeset -x first=inside1; typeset +g -x second=inside2; typeset -g -x third=inside3; showit; } first=outside1 second=outside2 third=outside3 unsetopt globalexport setit showit setopt globalexport setit showit unfunction setit showit 0:GLOBAL_EXPORT option >inside1 scalar-local-export >inside2 scalar-local-export >inside3 scalar-export >outside1 scalar >outside2 scalar >inside3 scalar-export >inside1 scalar-export >inside2 scalar-local-export >inside3 scalar-export >inside1 scalar-export >outside2 scalar >inside3 scalar-export setopt globassign foo=tmp* print $foo unsetopt globassign foo=tmp* print $foo 0:GLOB_ASSIGN option >tmpcd tmpfile1 tmpfile2 >tmp* mkdir onlysomefiles touch onlysomefiles/.thisfile onlysomefiles/thatfile setopt globdots print onlysomefiles/* unsetopt globdots print onlysomefiles/* rm -rf onlysomefiles 0:GLOB_DOTS option >onlysomefiles/.thisfile onlysomefiles/thatfile >onlysomefiles/thatfile # we've tested this enough times already... # could add some stuff for other sorts of expansion foo='tmp*' setopt globsubst print ${foo} unsetopt globsubst print ${foo} 0:GLOB_SUBST option >tmpcd tmpfile1 tmpfile2 >tmp* setopt ignorebraces echo X{a,b}Y unsetopt ignorebraces echo X{a,b}Y 0:IGNORE_BRACES option >X{a,b}Y >XaY XbY setopt ksh_arrays array=(one two three) print $array $array[2] print ${array[0]} ${array[1]} ${array[2]} ${array[3]} unsetopt ksh_arrays print $array $array[2] print ${array[0]} ${array[1]} ${array[2]} ${array[3]} unset array 0:KSH_ARRAYS option >one one[2] >one two three >one two three two >one one two three fpath=(.) echo >foo 'echo foo loaded; foo() { echo foo run; }' echo >bar 'bar() { echo bar run; }' setopt kshautoload autoload foo bar foo bar unfunction foo bar unsetopt kshautoload autoload foo bar foo bar 0:KSH_AUTOLOAD option >foo loaded >foo run >bar run >foo loaded >bar run # ksh_glob is tested by the glob tests. setopt kshoptionprint globassign print set setopt | grep kshoptionprint setopt | grep globassign unsetopt kshoptionprint print unset setopt | grep kshoptionprint setopt | grep globassign unsetopt globassign 0:KSH_OPTION_PRINT option >set >kshoptionprint on >globassign on >unset >globassign setopt kshtypeset ktvars=(ktv1 ktv2) typeset ktfoo=`echo arg1 arg2` $ktvars print $+ktv1 $+ktv2 $+ktv3 print $ktfoo unsetopt kshtypeset typeset noktfoo=`echo noktarg1 noktarg2` print $noktfoo print $+noktarg1 $+noktarg2 unset ktfoo ktv1 ktv2 noktfoo noktarg2 0:KSH_TYPESET option >1 1 0 >arg1 arg2 >noktarg1 >0 1 showopt() { setopt | egrep 'localoptions|ksharrays'; } f1() { setopt localoptions ksharrays; showopt } f2() { setopt ksharrays; showopt } setopt kshoptionprint showopt f1 showopt f2 showopt unsetopt ksh_arrays 0:LOCAL_OPTIONS option >ksharrays off >localoptions off >ksharrays on >localoptions on >ksharrays off >localoptions off >ksharrays on >localoptions off >ksharrays on >localoptions off # LOCAL_TRAPS was tested in C03traps (phew). fn() { local HOME=/any/old/name print -l var=~ 'anything goes/here'=~ split=`echo maybe not`; } setopt magicequalsubst fn setopt kshtypeset fn unsetopt magicequalsubst kshtypeset fn 0:MAGIC_EQUAL_SUBST option >var=/any/old/name >anything goes/here=/any/old/name >split=maybe >not >var=/any/old/name >anything goes/here=/any/old/name >split=maybe not >var=~ >anything goes/here=~ >split=maybe >not setopt MARK_DIRS print tmp* unsetopt MARK_DIRS print tmp* 0:MARK_DIRS option >tmpcd/ tmpfile1 tmpfile2 >tmpcd tmpfile1 tmpfile2 # maybe should be in A04redirect print "This is in1" >in1 print "This is in2" >in2 unsetopt multios print Test message >foo1 >foo2 print foo1: $(foo1 >foo2 sleep 1 # damn, race in multios print foo1: $(foo1: >foo2: Test message >This is in2 >foo1: Test message >foo2: Test message >This is in1 >This is in2 # tried this with other things, but not on its own, so much. unsetopt nomatch print with nonomatch: flooble* setopt nomatch print with nomatch flooble* 1:NOMATCH option >with nonomatch: flooble* ?ZTST_execchunk:2: no matches found: flooble* # NULL_GLOB should override NONOMATCH... setopt nullglob nomatch print frooble* tmp* unsetopt nullglob nomatch print frooble* tmp* 0:NULL_GLOB option >tmpcd tmpfile1 tmpfile2 >frooble* tmpcd tmpfile1 tmpfile2 touch ngs1.txt ngs2.txt ngs10.txt ngs20.txt ngs100.txt ngs200.txt setopt numericglobsort print -l ngs* unsetopt numericglobsort print -l ngs* 0:NUMERIC_GLOB_SORT option >ngs1.txt >ngs2.txt >ngs10.txt >ngs20.txt >ngs100.txt >ngs200.txt >ngs1.txt >ngs10.txt >ngs100.txt >ngs2.txt >ngs20.txt >ngs200.txt typeset -i 10 oznum setopt octalzeroes (( oznum = 012 + 013 )) print $oznum unsetopt octalzeroes (( oznum = 012 + 013 )) print $oznum unset oznum 0:OCTAL_ZEROES options >21 >25 typeset -a oldpath oldpath=($path) mkdir pdt_topdir pathtestdir pdt_topdir/pathtestdir print "#!/bin/sh\necho File in upper dir" >pathtestdir/findme print "#!/bin/sh\necho File in lower dir" >pdt_topdir/pathtestdir/findme chmod u+x pathtestdir/findme pdt_topdir/pathtestdir/findme pathtestdir/findme rm -f pathtestdir/findme setopt pathdirs path=($PWD $PWD/pdt_topdir) pathtestdir/findme print unsetting option... unsetopt pathdirs pathtestdir/findme path=($oldpath) unset $oldpath rm -rf pdt_topdir pathtestdir 0:PATH_DIRS option >File in upper dir >File in lower dir >unsetting option... ?ZTST_execchunk:2: no such file or directory: pathtestdir/findme setopt posixbuiltins PATH= command print foo unsetopt posixbuiltins print unsetting... PATH= command print foo 1:POSIX_BUILTINS option >foo >unsetting... ?ZTST_execchunk:2: command not found: print # This option seems to be problematic. I don't quite know how it works. ## func() { ## setopt localoptions printexitvalue ## false ## } ## func ## 1:PRINT_EXIT_VALUE option ## ?ZTST_execchunk:2: exit 1 setopt promptbang print -P ! setopt nopromptbang print -P ! 0:PROMPT_BANG option >0 >! unsetopt promptpercent print -P '%/' setopt promptpercent print -P '%/' 0q:PROMPT_PERCENT option >%/ >$mydir setopt promptsubst print -P '`echo waaah`' unsetopt promptsubst print -P '`echo waaah`' 0:PROMPT_SUBST option >waaah >`echo waaah` dirs pushd $mydir/tmpcd dirs pushd $mydir/tmpcd dirs setopt pushdignoredups pushd $mydir/tmpcd dirs unsetopt pushdignoredups popd >/dev/null popd >/dev/null 0q:PUSHD_IGNOREDUPS option >$mydirt >$mydirt/tmpcd $mydirt >$mydirt/tmpcd $mydirt/tmpcd $mydirt >$mydirt/tmpcd $mydirt/tmpcd $mydirt mkdir newcd cd $mydir pushd $mydir/tmpcd pushd $mydir/newcd dirs pushd -0 dirs setopt pushdminus pushdsilent pushd -0 dirs unsetopt pushdminus popd >/dev/null popd >/dev/null cd $mydir 0q:PUSHD_MINUS option >$mydirt/newcd $mydirt/tmpcd $mydirt >$mydirt $mydirt/newcd $mydirt/tmpcd >$mydirt $mydirt/newcd $mydirt/tmpcd # Do you have any idea how dull this is? pushd $mydir/tmpcd pushd dirs setopt pushdtohome pushd dirs unsetopt pushdtohome popd pushd popd dirs 0q:PUSHD_TO_HOME option >$mydirt $mydirt/tmpcd >~ $mydirt $mydirt/tmpcd >$mydirt array=(one two three four) setopt rcexpandparam print aa${array}bb unsetopt rcexpandparam print aa${array}bb 0:RC_EXPAND_PARAM option >aaonebb aatwobb aathreebb aafourbb >aaone two three fourbb setopt rcquotes # careful, this is done when parsing a complete block eval "print 'one''quoted''expression'" unsetopt rcquotes eval "print 'another''quoted''expression'" 0:RC_QUOTES option >one'quoted'expression >anotherquotedexpression # too lazy to test jobs -Z and ARGV0. (setopt restricted; cd /) (setopt restricted; PATH=/bin:/usr/bin) (setopt restricted; /bin/ls) (setopt restricted; hash ls=/bin/ls) (setopt restricted; print ha >outputfile) (setopt restricted; exec ls) (setopt restricted; unsetopt restricted) : 0:RESTRICTED option ?ZTST_execchunk:cd:2: restricted ?ZTST_execchunk:2: PATH: restricted ?ZTST_execchunk:2: /bin/ls: restricted ?ZTST_execchunk:hash:2: restricted: /bin/ls ?ZTST_execchunk:2: writing redirection not allowed in restricted mode ?ZTST_execchunk:exec:2: ls: restricted ?ZTST_execchunk:unsetopt:2: can't change option: restricted fn() { print =ls ={ls,} local foo='=ls' print ${~foo} } setopt shfileexpansion fn unsetopt shfileexpansion fn 0q:SH_FILE_EXPANSION option >$lspath =ls = >=ls >$lspath $lspath = >$lspath testpat() { if [[ $1 = ${~2} ]]; then print $1 $2 yes; else print $1 $2 no; fi } print option on setopt shglob repeat 2; do for str in 'a(b|c)' ab; do testpat $str 'a(b|c)' done for str in 'a<1-10>' a9; do testpat $str 'a<1-10>' done [[ ! -o shglob ]] && break print option off unsetopt shglob done 0:SH_GLOB option >option on >a(b|c) a(b|c) yes >ab a(b|c) no >a<1-10> a<1-10> yes >a9 a<1-10> no >option off >a(b|c) a(b|c) no >ab a(b|c) yes >a<1-10> a<1-10> no >a9 a<1-10> yes print this is bar >bar fn() { local NULLCMD=cat READNULLCMD=cat echo hello | >foo cat foo option set >option unset >hello >this is bar fn() { eval 'for f in foo bar; print $f' eval 'for f (word1 word2) print $f' eval 'repeat 3 print nonsense' } unsetopt shortloops print option unset fn setopt shortloops print option set fn 0:SHORT_LOOPS option >option unset >option set >foo >bar >word1 >word2 >nonsense >nonsense >nonsense ?fn:-1: parse error near `print' ?fn:-1: parse error near `print' ?fn:-1: parse error near `print' # Eugh, that line numbering behaviour with eval is probably a bug. fn() { print -l $*; } setopt shwordsplit print option set repeat 2; do foo='two words' fn $foo fn "${=foo}" [[ ! -o shwordsplit ]] && break unsetopt shwordsplit print option unset done 0:SH_WORD_SPLIT option >option set >two >words >two >words >option unset >two words >two >words fn() { unset foo; print $foo; } setopt nounset print option unset unset by setting nounset eval fn print option unset reset setopt unset fn 0:UNSET option >option unset unset by setting nounset >option unset reset > ?fn: foo: parameter not set # This really just tests if XTRACE is egregiously broken. # To test it properly would need a full set of its own. fn() { print message; } setopt xtrace fn unsetopt xtrace fn 0:XTRACE option >message >message ?+ZTST_execchunk:2> fn ?+fn:0> print message ?+ZTST_execchunk:2> unsetopt xtrace