Home | History | Annotate | Line # | Download | only in sh
t_cmdsub.sh revision 1.3
      1  1.3  christos # $NetBSD: t_cmdsub.sh,v 1.3 2016/03/31 16:20:39 christos Exp $
      2  1.1  christos #
      3  1.1  christos # Copyright (c) 2016 The NetBSD Foundation, Inc.
      4  1.1  christos # All rights reserved.
      5  1.1  christos #
      6  1.1  christos # Redistribution and use in source and binary forms, with or without
      7  1.1  christos # modification, are permitted provided that the following conditions
      8  1.1  christos # are met:
      9  1.1  christos # 1. Redistributions of source code must retain the above copyright
     10  1.1  christos #    notice, this list of conditions and the following disclaimer.
     11  1.1  christos # 2. Redistributions in binary form must reproduce the above copyright
     12  1.1  christos #    notice, this list of conditions and the following disclaimer in the
     13  1.1  christos #    documentation and/or other materials provided with the distribution.
     14  1.1  christos #
     15  1.1  christos # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     16  1.1  christos # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     17  1.1  christos # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     18  1.1  christos # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     19  1.1  christos # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     20  1.1  christos # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     21  1.1  christos # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22  1.1  christos # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     23  1.1  christos # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     24  1.1  christos # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25  1.1  christos # POSSIBILITY OF SUCH DAMAGE.
     26  1.1  christos #
     27  1.1  christos # the implementation of "sh" to test
     28  1.1  christos : ${TEST_SH:="/bin/sh"}
     29  1.1  christos 
     30  1.1  christos #
     31  1.1  christos # This file tests command substitutions ( `...` and $( ... ) )
     32  1.1  christos #
     33  1.1  christos # CAUTION:
     34  1.1  christos #	Be careful attempting running these tests outside the ATF environment
     35  1.1  christos #	Some of the tests run "rm *" in the current directory to clean up
     36  1.1  christos #	An ATF test directory should be empty already, outside ATF, anything
     37  1.1  christos 
     38  1.1  christos atf_test_case a_basic_cmdsub
     39  1.1  christos a_basic_cmdsub_head() {
     40  1.1  christos 	atf_set "descr" 'Test operation of simple $( ) substitutions'
     41  1.1  christos }
     42  1.1  christos a_basic_cmdsub_body() {
     43  1.1  christos 	atf_check -s exit:0 -o match:'Result is true today' -e empty \
     44  1.1  christos 	    ${TEST_SH} -c \
     45  1.1  christos 		'echo Result is $( true && echo true || echo false ) today'
     46  1.1  christos 
     47  1.1  christos 	atf_check -s exit:0 -o match:'Result is false today' -e empty \
     48  1.1  christos 	    ${TEST_SH} -c \
     49  1.1  christos 		'echo Result is $( false && echo true || echo false ) today'
     50  1.1  christos 
     51  1.1  christos 	atf_check -s exit:0 -o match:'aaabbbccc' -e empty \
     52  1.1  christos 	    ${TEST_SH} -c 'echo aaa$( echo bbb )ccc'
     53  1.1  christos 	atf_check -s exit:0 -o match:'aaabbb cccddd' -e empty \
     54  1.1  christos 	    ${TEST_SH} -c 'echo aaa$( echo bbb ccc )ddd'
     55  1.1  christos 	atf_check -s exit:0 -o inline:'aaabbb cccddd\n' -e empty \
     56  1.1  christos 	    ${TEST_SH} -c 'echo aaa$( echo bbb; echo ccc )ddd'
     57  1.1  christos 	atf_check -s exit:0 -o inline:'aaabbb\ncccddd\n' -e empty \
     58  1.1  christos 	    ${TEST_SH} -c 'echo "aaa$( echo bbb; echo ccc )ddd"'
     59  1.1  christos 
     60  1.1  christos 	atf_check -s exit:0 -o inline:'some string\n' -e empty \
     61  1.1  christos 	    ${TEST_SH} -c 'X=$( echo some string ); echo "$X"'
     62  1.1  christos 	atf_check -s exit:0 -o inline:'weird; string *\n' -e empty \
     63  1.1  christos 	    ${TEST_SH} -c 'X=$( echo "weird; string *" ); echo "$X"'
     64  1.1  christos 
     65  1.1  christos 	rm -f * 2>/dev/null || :
     66  1.1  christos 	for f in file-1 file-2
     67  1.1  christos 	do
     68  1.1  christos 		cp /dev/null "$f"
     69  1.1  christos 	done
     70  1.1  christos 
     71  1.1  christos 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
     72  1.1  christos 	    ${TEST_SH} -c 'echo Found $( echo * )'
     73  1.1  christos 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
     74  1.1  christos 	    ${TEST_SH} -c 'echo Found "$( echo * )"'
     75  1.1  christos 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
     76  1.1  christos 	    ${TEST_SH} -c 'echo Found $('" echo '*' )"
     77  1.1  christos 	atf_check -s exit:0 -o match:'Found \*' -e empty \
     78  1.1  christos 	    ${TEST_SH} -c 'echo Found "$('" echo '*' "')"'
     79  1.1  christos 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
     80  1.1  christos 	    ${TEST_SH} -c 'echo Found $('" echo \\* )"
     81  1.1  christos 	atf_check -s exit:0 -o match:'Found \*' -e empty \
     82  1.1  christos 	    ${TEST_SH} -c 'echo Found "$('" echo \\* )"\"
     83  1.1  christos }
     84  1.1  christos 
     85  1.1  christos atf_test_case b_basic_backticks
     86  1.1  christos b_basic_backticks_head() {
     87  1.1  christos 	atf_set "descr" 'Test operation of old style ` ` substitutions'
     88  1.1  christos }
     89  1.1  christos b_basic_backticks_body() {
     90  1.1  christos 	atf_check -s exit:0 -o match:'Result is true today' -e empty \
     91  1.1  christos 	    ${TEST_SH} -c \
     92  1.1  christos 		'echo Result is `true && echo true || echo false` today'
     93  1.1  christos 
     94  1.1  christos 	atf_check -s exit:0 -o match:'Result is false today' -e empty \
     95  1.1  christos 	    ${TEST_SH} -c \
     96  1.1  christos 		'echo Result is `false && echo true || echo false` today'
     97  1.1  christos 
     98  1.1  christos 	atf_check -s exit:0 -o match:'aaabbbccc' -e empty \
     99  1.1  christos 	    ${TEST_SH} -c 'echo aaa` echo bbb `ccc'
    100  1.1  christos 	atf_check -s exit:0 -o match:'aaabbb cccddd' -e empty \
    101  1.1  christos 	    ${TEST_SH} -c 'echo aaa` echo bbb ccc `ddd'
    102  1.1  christos 	atf_check -s exit:0 -o inline:'aaabbb cccddd\n' -e empty \
    103  1.1  christos 	    ${TEST_SH} -c 'echo aaa` echo bbb; echo ccc `ddd'
    104  1.1  christos 	atf_check -s exit:0 -o inline:'aaabbb\ncccddd\n' -e empty \
    105  1.1  christos 	    ${TEST_SH} -c 'echo "aaa` echo bbb; echo ccc `ddd"'
    106  1.1  christos 
    107  1.1  christos 	atf_check -s exit:0 -o inline:'some string\n' -e empty \
    108  1.1  christos 	    ${TEST_SH} -c 'X=` echo some string `; echo "$X"'
    109  1.1  christos 	atf_check -s exit:0 -o inline:'weird; string *\n' -e empty \
    110  1.1  christos 	    ${TEST_SH} -c 'X=` echo "weird; string *" `; echo "$X"'
    111  1.1  christos 
    112  1.1  christos 	rm -f * 2>/dev/null || :
    113  1.1  christos 	for f in file-1 file-2
    114  1.1  christos 	do
    115  1.1  christos 		cp /dev/null "$f"
    116  1.1  christos 	done
    117  1.1  christos 
    118  1.1  christos 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
    119  1.1  christos 	    ${TEST_SH} -c 'echo Found ` echo * `'
    120  1.1  christos 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
    121  1.1  christos 	    ${TEST_SH} -c 'echo Found "` echo * `"'
    122  1.1  christos 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
    123  1.1  christos 	    ${TEST_SH} -c 'echo Found `'" echo '*' "'`'
    124  1.1  christos 	atf_check -s exit:0 -o match:'Found \*' -e empty \
    125  1.1  christos 	    ${TEST_SH} -c 'echo Found "`'" echo '*' "'`"'
    126  1.1  christos 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
    127  1.1  christos 	    ${TEST_SH} -c 'echo Found `'" echo \\* "'`'
    128  1.1  christos 	atf_check -s exit:0 -o match:'Found \*' -e empty \
    129  1.1  christos 	    ${TEST_SH} -c 'echo Found "`'" echo \\* "'`"'
    130  1.1  christos }
    131  1.1  christos 
    132  1.1  christos atf_test_case c_nested_cmdsub
    133  1.1  christos c_nested_cmdsub_head() {
    134  1.1  christos 	atf_set "descr" "Test that cmd substitutions can be nested"
    135  1.1  christos }
    136  1.1  christos c_nested_cmdsub_body() {
    137  1.1  christos 	atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
    138  1.1  christos 	    ${TEST_SH} -c 'echo __$( echo foo$(echo bar)bletch )__'
    139  1.1  christos 	atf_check -s exit:0 -o match:'_abcde_' -e empty \
    140  1.1  christos 	    ${TEST_SH} -c 'echo _$(echo a$(echo $(echo b)c$(echo d))e )_'
    141  1.1  christos 	atf_check -s exit:0 -o match:'123454321' -e empty \
    142  1.1  christos 	    ${TEST_SH} -c 'echo 1$(echo 2$(echo 3$(echo 4$(echo 5)4)3)2)1'
    143  1.1  christos }
    144  1.1  christos 
    145  1.1  christos atf_test_case d_nested_backticks
    146  1.1  christos d_nested_backticks_head() {
    147  1.1  christos 	atf_set "descr" "Tests that old style backtick cmd subs can be nested"
    148  1.1  christos }
    149  1.1  christos d_nested_backticks_body() {
    150  1.1  christos 	atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
    151  1.1  christos 	    ${TEST_SH} -c 'echo __` echo foo\`echo bar\`bletch `__'
    152  1.1  christos 	atf_check -s exit:0 -o match:'_abcde_' -e empty \
    153  1.1  christos 	    ${TEST_SH} -c \
    154  1.1  christos 		'echo _`echo a\`echo \\\`echo b\\\`c\\\`echo d\\\`\`e `_'
    155  1.1  christos 	atf_check -s exit:0 -o match:'123454321' -e empty \
    156  1.1  christos 	    ${TEST_SH} -c \
    157  1.1  christos 	    'echo 1`echo 2\`echo 3\\\`echo 4\\\\\\\`echo 5\\\\\\\`4\\\`3\`2`1'
    158  1.1  christos }
    159  1.1  christos 
    160  1.1  christos atf_test_case e_perverse_mixing
    161  1.1  christos e_perverse_mixing_head() {
    162  1.1  christos 	atf_set "descr" \
    163  1.1  christos 		"Checks various mixed new and old style cmd substitutions"
    164  1.1  christos }
    165  1.1  christos e_perverse_mixing_body() {
    166  1.1  christos 	atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
    167  1.1  christos 	    ${TEST_SH} -c 'echo __$( echo foo`echo bar`bletch )__'
    168  1.1  christos 	atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
    169  1.1  christos 	    ${TEST_SH} -c 'echo __` echo foo$(echo bar)bletch `__'
    170  1.1  christos 	atf_check -s exit:0 -o match:'_abcde_' -e empty \
    171  1.1  christos 	    ${TEST_SH} -c 'echo _$(echo a`echo $(echo b)c$(echo d)`e )_'
    172  1.1  christos 	atf_check -s exit:0 -o match:'_abcde_' -e empty \
    173  1.1  christos 	    ${TEST_SH} -c 'echo _`echo a$(echo \`echo b\`c\`echo d\`)e `_'
    174  1.1  christos 	atf_check -s exit:0 -o match:'12345654321' -e empty \
    175  1.1  christos 	    ${TEST_SH} -c \
    176  1.1  christos 		'echo 1`echo 2$(echo 3\`echo 4\\\`echo 5$(echo 6)5\\\`4\`3)2`1'
    177  1.1  christos }
    178  1.1  christos 
    179  1.1  christos atf_test_case f_redirect_in_cmdsub
    180  1.1  christos f_redirect_in_cmdsub_head() {
    181  1.1  christos 	atf_set "descr" "Checks that redirects work in command substitutions"
    182  1.1  christos }
    183  1.1  christos f_redirect_in_cmdsub_body() {
    184  1.2  christos 	atf_require_prog cat
    185  1.2  christos 	atf_require_prog rm
    186  1.2  christos 
    187  1.1  christos 	rm -f file 2>/dev/null || :
    188  1.1  christos 	atf_check -s exit:0 -o match:'_aa_' -e empty \
    189  1.1  christos 	    ${TEST_SH} -c 'echo _$( echo a$( echo b > file )a)_'
    190  1.1  christos 	atf_check -s exit:0 -o match:b -e empty ${TEST_SH} -c 'cat file'
    191  1.1  christos 	atf_check -s exit:0 -o match:'_aba_' -e empty \
    192  1.1  christos 	    ${TEST_SH} -c 'echo _$( echo a$( cat < file )a)_'
    193  1.1  christos 	atf_check -s exit:0 -o match:'_aa_' -e empty \
    194  1.1  christos 	    ${TEST_SH} -c 'echo _$( echo a$( echo d >> file )a)_'
    195  1.1  christos 	atf_check -s exit:0 -o inline:'b\nd\n' -e empty ${TEST_SH} -c 'cat file'
    196  1.1  christos 	atf_check -s exit:0 -o match:'_aa_' -e match:'not error' \
    197  1.1  christos 	    ${TEST_SH} -c 'echo _$( echo a$( echo not error >&2 )a)_'
    198  1.1  christos }
    199  1.1  christos 
    200  1.1  christos atf_test_case g_redirect_in_backticks
    201  1.1  christos g_redirect_in_backticks_head() {
    202  1.1  christos 	atf_set "descr" "Checks that redirects work in old style cmd sub"
    203  1.1  christos }
    204  1.1  christos g_redirect_in_backticks_body() {
    205  1.2  christos 	atf_require_prog cat
    206  1.2  christos 	atf_require_prog rm
    207  1.2  christos 
    208  1.1  christos 	rm -f file 2>/dev/null || :
    209  1.1  christos 	atf_check -s exit:0 -o match:'_aa_' -e empty \
    210  1.1  christos 	    ${TEST_SH} -c 'echo _` echo a\` echo b > file \`a`_'
    211  1.1  christos 	atf_check -s exit:0 -o match:b -e empty ${TEST_SH} -c 'cat file'
    212  1.1  christos 	atf_check -s exit:0 -o match:'_aba_' -e empty \
    213  1.1  christos 	    ${TEST_SH} -c 'echo _` echo a\` cat < file \`a`_'
    214  1.1  christos 	atf_check -s exit:0 -o match:'_aa_' -e empty \
    215  1.1  christos 	    ${TEST_SH} -c 'echo _` echo a\` echo d >> file \`a`_'
    216  1.1  christos 	atf_check -s exit:0 -o inline:'b\nd\n' -e empty ${TEST_SH} -c 'cat file'
    217  1.1  christos 	atf_check -s exit:0 -o match:'_aa_' -e match:'not error' \
    218  1.1  christos 	    ${TEST_SH} -c 'echo _` echo a\` echo not error >&2 \`a`_'
    219  1.1  christos }
    220  1.1  christos 
    221  1.1  christos atf_test_case h_vars_in_cmdsub
    222  1.1  christos h_vars_in_cmdsub_head() {
    223  1.1  christos 	atf_set "descr" "Check that variables work in command substitutions"
    224  1.1  christos }
    225  1.1  christos h_vars_in_cmdsub_body() {
    226  1.1  christos 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    227  1.1  christos 	    ${TEST_SH} -c 'X=abc; echo __$( echo ${X} )__'
    228  1.1  christos 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    229  1.1  christos 	    ${TEST_SH} -c 'X=abc; echo __$( echo "${X}" )__'
    230  1.1  christos 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    231  1.1  christos 	    ${TEST_SH} -c 'X=abc; echo "__$( echo ${X} )__"'
    232  1.1  christos 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    233  1.1  christos 	    ${TEST_SH} -c 'X=abc; echo "__$( echo "${X}" )__"'
    234  1.1  christos 
    235  1.1  christos 	atf_check -s exit:0 -o inline:'a\n\nb\n\nc\n' -e empty \
    236  1.1  christos 	    ${TEST_SH} -c "for X in a '' b '' c"'; do echo $( echo "$X" ); done'
    237  1.1  christos 
    238  1.1  christos 	atf_check -s exit:0 -o match:'__acd__' -e empty \
    239  1.1  christos 	    ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X-b}${Y-c}d)__"'
    240  1.1  christos 	atf_check -s exit:0 -o match:'__abcd__' -e empty \
    241  1.1  christos 	    ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X:-b}${Y:-c}d)__"'
    242  1.1  christos 	atf_check -s exit:0 -o match:'__XYX__' -e empty \
    243  1.1  christos 	    ${TEST_SH} -c 'X=X; echo "__${X}$( X=Y; echo ${X} )${X}__"'
    244  1.1  christos 	atf_check -s exit:0 -o match:'__def__' -e empty \
    245  1.1  christos 	    ${TEST_SH} -c 'X=abc; echo "__$(X=def; echo "${X}" )__"'
    246  1.1  christos 	atf_check -s exit:0 -o inline:'abcdef\nabc\n' -e empty \
    247  1.1  christos 	    ${TEST_SH} -c 'X=abc; echo "$X$(X=def; echo ${X} )"; echo $X'
    248  1.1  christos }
    249  1.1  christos 
    250  1.1  christos atf_test_case i_vars_in_backticks
    251  1.1  christos i_vars_in_backticks_head() {
    252  1.1  christos 	atf_set "descr" "Checks that variables work in old style cmd sub"
    253  1.1  christos }
    254  1.1  christos i_vars_in_backticks_body() {
    255  1.1  christos 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    256  1.1  christos 	    ${TEST_SH} -c 'X=abc; echo __` echo ${X} `__'
    257  1.1  christos 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    258  1.1  christos 	    ${TEST_SH} -c 'X=abc; echo __` echo "${X}" `__'
    259  1.1  christos 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    260  1.1  christos 	    ${TEST_SH} -c 'X=abc; echo "__` echo ${X} `__"'
    261  1.1  christos 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    262  1.1  christos 	    ${TEST_SH} -c 'X=abc; echo "__` echo \"${X}\" `__"'
    263  1.1  christos 
    264  1.1  christos 	atf_check -s exit:0 -o inline:'a\n\nb\n\nc\n' -e empty \
    265  1.1  christos 	    ${TEST_SH} -c "for X in a '' b '' c"'; do echo $( echo "$X" ); done'
    266  1.1  christos 
    267  1.1  christos 	atf_check -s exit:0 -o match:'__acd__' -e empty \
    268  1.1  christos 	    ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X-b}${Y-c}d)__"'
    269  1.1  christos 	atf_check -s exit:0 -o match:'__abcd__' -e empty \
    270  1.1  christos 	    ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X:-b}${Y:-c}d)__"'
    271  1.1  christos 	atf_check -s exit:0 -o match:'__XYX__' -e empty \
    272  1.1  christos 	    ${TEST_SH} -c 'X=X; echo "__${X}$( X=Y; echo ${X} )${X}__"'
    273  1.1  christos 	atf_check -s exit:0 -o inline:'abcdef\nabc\n' -e empty \
    274  1.1  christos 	    ${TEST_SH} -c 'X=abc; echo "$X`X=def; echo \"${X}\" `";echo $X'
    275  1.1  christos 
    276  1.1  christos 	# The following is nonsense, so is not included ...
    277  1.1  christos 	# atf_check -s exit:0 -o match:'__abc__' -e empty \
    278  1.1  christos 	#                              oV             cV   oV   cV
    279  1.1  christos 	#    ${TEST_SH} -c 'X=abc; echo "__`X=def echo "${X}" `__"'
    280  1.1  christos 	#				   `start in " ^ " ends, ` not yet
    281  1.1  christos }
    282  1.1  christos 
    283  1.1  christos atf_test_case j_cmdsub_in_varexpand
    284  1.1  christos j_cmdsub_in_varexpand_head() {
    285  1.1  christos 	atf_set "descr" "Checks that command sub can be used in var expansion"
    286  1.1  christos }
    287  1.1  christos j_cmdsub_in_varexpand_body() {
    288  1.1  christos 	atf_check -s exit:0 -o match:'foo' -e empty \
    289  1.1  christos 	    ${TEST_SH} -c 'X=set; echo ${X+$(echo foo)}'
    290  1.1  christos 	atf_check -s exit:0 -o match:'set' -e empty \
    291  1.1  christos 	    ${TEST_SH} -c 'X=set; echo ${X-$(echo foo)}'
    292  1.1  christos 	rm -f bar 2>/dev/null || :
    293  1.1  christos 	atf_check -s exit:0 -o match:'set' -e empty \
    294  1.1  christos 	    ${TEST_SH} -c 'X=set; echo ${X-$(echo foo > bar)}'
    295  1.1  christos 	test -f bar && atf_fail "bar should not exist, but does"
    296  1.1  christos 	atf_check -s exit:0 -o inline:'\n' -e empty \
    297  1.1  christos 	    ${TEST_SH} -c 'X=set; echo ${X+$(echo foo > bar)}'
    298  1.1  christos 	test -f bar || atf_fail "bar should exist, but does not"
    299  1.1  christos }
    300  1.1  christos 
    301  1.1  christos atf_test_case k_backticks_in_varexpand
    302  1.1  christos k_backticks_in_varexpand_head() {
    303  1.1  christos 	atf_set "descr" "Checks that old style cmd sub works in var expansion"
    304  1.1  christos }
    305  1.1  christos k_backticks_in_varexpand_body() {
    306  1.1  christos 	atf_check -s exit:0 -o match:'foo' -e empty \
    307  1.1  christos 	    ${TEST_SH} -c 'X=set; echo ${X+`echo foo`}'
    308  1.1  christos 	atf_check -s exit:0 -o match:'set' -e empty \
    309  1.1  christos 	    ${TEST_SH} -c 'X=set; echo ${X-`echo foo`}'
    310  1.1  christos 	rm -f bar 2>/dev/null || :
    311  1.1  christos 	atf_check -s exit:0 -o match:'set' -e empty \
    312  1.1  christos 	    ${TEST_SH} -c 'X=set; echo ${X-`echo foo > bar`}'
    313  1.1  christos 	test -f bar && atf_fail "bar should not exist, but does"
    314  1.1  christos 	atf_check -s exit:0 -o inline:'\n' -e empty \
    315  1.1  christos 	    ${TEST_SH} -c 'X=set; echo ${X+`echo foo > bar`}'
    316  1.1  christos 	test -f bar || atf_fail "bar should exist, but does not"
    317  1.1  christos }
    318  1.1  christos 
    319  1.1  christos atf_test_case l_arithmetic_in_cmdsub
    320  1.1  christos l_arithmetic_in_cmdsub_head() {
    321  1.1  christos 	atf_set "descr" "Checks that arithmetic works in cmd substitutions"
    322  1.1  christos }
    323  1.1  christos l_arithmetic_in_cmdsub_body() {
    324  1.1  christos 	atf_check -s exit:0 -o inline:'1 + 1 = 2\n' -e empty \
    325  1.1  christos 	    ${TEST_SH} -c 'echo 1 + 1 = $( echo $(( 1 + 1 )) )'
    326  1.1  christos 	atf_check -s exit:0 -o inline:'X * Y = 6\n' -e empty \
    327  1.1  christos 	    ${TEST_SH} -c 'X=2; Y=3; echo X \* Y = $( echo $(( X * Y )) )'
    328  1.1  christos 	atf_check -s exit:0 -o inline:'Y % X = 1\n' -e empty \
    329  1.1  christos 	    ${TEST_SH} -c 'X=2; Y=3; echo Y % X = $( echo $(( $Y % $X )) )'
    330  1.1  christos }
    331  1.1  christos 
    332  1.1  christos atf_test_case m_arithmetic_in_backticks
    333  1.1  christos m_arithmetic_in_backticks_head() {
    334  1.1  christos 	atf_set "descr" "Checks that arithmetic works in old style cmd sub"
    335  1.1  christos }
    336  1.1  christos m_arithmetic_in_backticks_body() {
    337  1.1  christos 	atf_check -s exit:0 -o inline:'2 + 3 = 5\n' -e empty \
    338  1.1  christos 	    ${TEST_SH} -c 'echo 2 + 3 = ` echo $(( 2 + 3 )) `'
    339  1.1  christos 	atf_check -s exit:0 -o inline:'X * Y = 6\n' -e empty \
    340  1.1  christos 	    ${TEST_SH} -c 'X=2; Y=3; echo X \* Y = ` echo $(( X * Y )) `'
    341  1.1  christos 	atf_check -s exit:0 -o inline:'Y % X = 1\n' -e empty \
    342  1.1  christos 	    ${TEST_SH} -c 'X=2; Y=3; echo Y % X = ` echo $(( $Y % $X )) `'
    343  1.1  christos }
    344  1.1  christos 
    345  1.1  christos atf_test_case n_cmdsub_in_arithmetic
    346  1.1  christos n_cmdsub_in_arithmetic_head() {
    347  1.1  christos 	atf_set "descr" "Tests uses of command substitutions in arithmetic"
    348  1.1  christos }
    349  1.1  christos n_cmdsub_in_arithmetic_body() {
    350  1.1  christos 	atf_check -s exit:0 -o inline:'7\n' -e empty \
    351  1.1  christos 	    ${TEST_SH} -c 'echo $(( $( echo 3 ) $( echo + ) $( echo 4 ) ))'
    352  1.1  christos 	atf_check -s exit:0 -o inline:'11\n7\n18\n4\n1\n' -e empty \
    353  1.1  christos 	    ${TEST_SH} -c \
    354  1.1  christos 		 'for op in + - \* / %
    355  1.1  christos 		  do
    356  1.1  christos 		      echo $(( $( echo 9 ) $( echo "${op}" ) $( echo 2 ) ))
    357  1.1  christos 		  done'
    358  1.1  christos }
    359  1.1  christos 
    360  1.1  christos atf_test_case o_backticks_in_arithmetic
    361  1.1  christos o_backticks_in_arithmetic_head() {
    362  1.1  christos 	atf_set "descr" "Tests old style cmd sub used in arithmetic"
    363  1.1  christos }
    364  1.1  christos o_backticks_in_arithmetic_body() {
    365  1.1  christos 	atf_check -s exit:0 -o inline:'33\n' -e empty \
    366  1.1  christos 	    ${TEST_SH} -c 'echo $(( `echo 77` `echo -` `echo 44`))'
    367  1.1  christos 	atf_check -s exit:0 -o inline:'14\n8\n33\n3\n2\n' -e empty \
    368  1.1  christos 	    ${TEST_SH} -c \
    369  1.1  christos 		 'for op in + - \* / %
    370  1.1  christos 		  do
    371  1.1  christos 		      echo $((`echo 11``echo "${op}"``echo 3`))
    372  1.1  christos 		  done'
    373  1.1  christos }
    374  1.1  christos 
    375  1.1  christos atf_test_case p_cmdsub_in_heredoc
    376  1.1  christos p_cmdsub_in_heredoc_head() {
    377  1.1  christos 	atf_set "descr" "Checks that cmdsubs work inside a here document"
    378  1.1  christos }
    379  1.1  christos p_cmdsub_in_heredoc_body() {
    380  1.2  christos 	atf_require_prog cat
    381  1.2  christos 
    382  1.1  christos 	atf_check -s exit:0 -o inline:'line 1+1\nline 2\nline 3\n' -e empty \
    383  1.1  christos 	    ${TEST_SH} -c \
    384  1.1  christos 		'cat <<- EOF
    385  1.1  christos 			$( echo line 1 )$( echo +1 )
    386  1.1  christos 			$( echo line 2;echo line 3 )
    387  1.1  christos 		EOF'
    388  1.1  christos }
    389  1.1  christos 
    390  1.1  christos atf_test_case q_backticks_in_heredoc
    391  1.1  christos q_backticks_in_heredoc_head() {
    392  1.1  christos 	atf_set "descr" "Checks that old style cmdsubs work in here docs"
    393  1.1  christos }
    394  1.1  christos q_backticks_in_heredoc_body() {
    395  1.2  christos 	atf_require_prog cat
    396  1.2  christos 
    397  1.1  christos 	atf_check -s exit:0 -o inline:'Mary had a\nlittle\nlamb\n' -e empty \
    398  1.1  christos 	    ${TEST_SH} -c \
    399  1.1  christos 		'cat <<- EOF
    400  1.1  christos 			`echo Mary ` `echo had a `
    401  1.1  christos 			` echo little; echo lamb `
    402  1.1  christos 		EOF'
    403  1.1  christos }
    404  1.1  christos 
    405  1.1  christos atf_test_case r_heredoc_in_cmdsub
    406  1.1  christos r_heredoc_in_cmdsub_head() {
    407  1.1  christos 	atf_set "descr" "Checks that here docs work inside cmd subs"
    408  1.1  christos }
    409  1.1  christos r_heredoc_in_cmdsub_body() {
    410  1.2  christos 	atf_require_prog cat
    411  1.2  christos 
    412  1.1  christos 	atf_check -s exit:0 -o inline:'Mary had a\nlittle\nlamb\n' -e empty \
    413  1.1  christos 	    ${TEST_SH} -c 'echo "$( cat <<- \EOF
    414  1.1  christos 				Mary had a
    415  1.1  christos 				little
    416  1.1  christos 				lamb
    417  1.1  christos 			EOF
    418  1.1  christos 			)"'
    419  1.1  christos 
    420  1.1  christos 	atf_check -s exit:0 -e empty \
    421  1.1  christos 	    -o inline:'Mary had 1\nlittle\nlamb\nMary had 4\nlittle\nlambs\n' \
    422  1.1  christos 	    ${TEST_SH} -c 'for N in 1 4; do echo "$( cat <<- EOF
    423  1.1  christos 				Mary had ${N}
    424  1.1  christos 				little
    425  1.1  christos 				lamb$( [ $N -gt 1 ] && echo s )
    426  1.1  christos 			EOF
    427  1.1  christos 			)"; done'
    428  1.1  christos 
    429  1.1  christos 
    430  1.1  christos 	atf_check -s exit:0 -o inline:'A Calculation:\n2 * 7 = 14\n' -e empty \
    431  1.1  christos 	    ${TEST_SH} -c 'echo "$( cat <<- EOF
    432  1.1  christos 				A Calculation:
    433  1.1  christos 					2 * 7 = $(( 2 * 7 ))
    434  1.1  christos 			EOF
    435  1.1  christos 			)"'
    436  1.1  christos 
    437  1.1  christos 	atf_check -s exit:0 -o inline:'Line 1\nLine 2\n' -e empty \
    438  1.1  christos 	    ${TEST_SH} -c 'echo "$( cat <<- "EOF" )"
    439  1.1  christos 				Line 1
    440  1.1  christos 				Line 2
    441  1.1  christos 				EOF
    442  1.1  christos 			'
    443  1.1  christos }
    444  1.1  christos 
    445  1.1  christos atf_test_case s_heredoc_in_backticks
    446  1.1  christos s_heredoc_in_backticks_head() {
    447  1.1  christos 	atf_set "descr" "Checks that here docs work inside old style cmd subs"
    448  1.1  christos }
    449  1.1  christos s_heredoc_in_backticks_body() {
    450  1.2  christos 	atf_require_prog cat
    451  1.2  christos 
    452  1.1  christos 	atf_check -s exit:0 -o inline:'Mary had a little lamb\n' -e empty \
    453  1.1  christos 	    ${TEST_SH} -c 'echo ` cat <<- \EOF
    454  1.1  christos 				Mary had a
    455  1.1  christos 				little
    456  1.1  christos 				lamb
    457  1.1  christos 			EOF
    458  1.1  christos 			`'
    459  1.1  christos 
    460  1.1  christos 	atf_check -s exit:0 -o inline:'A Calculation:\n17 / 3 = 5\n' -e empty \
    461  1.1  christos 	    ${TEST_SH} -c 'echo "` cat <<- EOF
    462  1.1  christos 				A Calculation:
    463  1.1  christos 					17 / 3 = $(( 17 / 3 ))
    464  1.1  christos 			EOF
    465  1.1  christos 			`"'
    466  1.1  christos }
    467  1.1  christos 
    468  1.1  christos atf_test_case t_nested_cmdsubs_in_heredoc
    469  1.1  christos t_nested_cmdsubs_in_heredoc_head() {
    470  1.1  christos 	atf_set "descr" "Checks nested command substitutions in here docs"
    471  1.1  christos }
    472  1.1  christos t_nested_cmdsubs_in_heredoc_body() {
    473  1.2  christos 	atf_require_prog cat
    474  1.2  christos 	atf_require_prog rm
    475  1.2  christos 
    476  1.2  christos 	rm -f * 2>/dev/null || :
    477  1.2  christos 	echo "Hello" > File
    478  1.2  christos 
    479  1.2  christos 	atf_check -s exit:0 -o inline:'Hello U\nHelp me!\n' -e empty \
    480  1.2  christos 	    ${TEST_SH} -c 'cat <<- EOF
    481  1.2  christos 		$(cat File) U
    482  1.2  christos 		$( V=$(cat File); echo "${V%lo}p" ) me!
    483  1.2  christos 		EOF'
    484  1.2  christos 
    485  1.2  christos 	rm -f * 2>/dev/null || :
    486  1.2  christos 	echo V>V ; echo A>A; echo R>R
    487  1.2  christos 	echo Value>VAR
    488  1.2  christos 
    489  1.2  christos 	atf_check -s exit:0 -o inline:'$2.50\n' -e empty \
    490  1.2  christos 	    ${TEST_SH} -c 'cat <<- EOF
    491  1.2  christos 	$(Value='\''$2.50'\'';eval echo $(eval $(cat V)$(cat A)$(cat R)=\'\''\$$(cat $(cat V)$(cat A)$(cat R))\'\''; eval echo \$$(set -- *;echo ${3}${1}${2})))
    492  1.2  christos 		EOF'
    493  1.1  christos }
    494  1.1  christos 
    495  1.1  christos atf_test_case u_nested_backticks_in_heredoc
    496  1.1  christos u_nested_backticks_in_heredoc_head() {
    497  1.1  christos 	atf_set "descr" "Checks nested old style cmd subs in here docs"
    498  1.1  christos }
    499  1.1  christos u_nested_backticks_in_heredoc_body() {
    500  1.2  christos 	atf_require_prog cat
    501  1.2  christos 	atf_require_prog rm
    502  1.2  christos 
    503  1.2  christos 	rm -f * 2>/dev/null || :
    504  1.2  christos 	echo "Hello" > File
    505  1.2  christos 
    506  1.2  christos 	atf_check -s exit:0 -o inline:'Hello U\nHelp me!\n' -e empty \
    507  1.2  christos 	    ${TEST_SH} -c 'cat <<- EOF
    508  1.2  christos 		`cat File` U
    509  1.2  christos 		`V=\`cat File\`; echo "${V%lo}p" ` me!
    510  1.2  christos 		EOF'
    511  1.2  christos 
    512  1.2  christos 	rm -f * 2>/dev/null || :
    513  1.2  christos 	echo V>V ; echo A>A; echo R>R
    514  1.2  christos 	echo Value>VAR
    515  1.2  christos 
    516  1.2  christos 	atf_check -s exit:0 -o inline:'$5.20\n' -e empty \
    517  1.2  christos 	    ${TEST_SH} -c 'cat <<- EOF
    518  1.2  christos 	`Value='\''$5.20'\'';eval echo \`eval \\\`cat V\\\`\\\`cat A\\\`\\\`cat R\\\`=\\\'\''\\\$\\\`cat \\\\\\\`cat V\\\\\\\`\\\\\\\`cat A\\\\\\\`\\\\\\\`cat R\\\\\\\`\\\`\\\'\''; eval echo \\\$\\\`set -- *;echo \\\\\${3}\\\\\${1}\\\\\${2}\\\`\``
    519  1.2  christos 		EOF'
    520  1.1  christos }
    521  1.1  christos 
    522  1.3  christos atf_test_case v_cmdsub_paren_tests
    523  1.3  christos v_cmdsub__paren_tests_head() {
    524  1.3  christos 	atf_set "descr" "tests with cmdsubs containing embedded ')'"
    525  1.3  christos }
    526  1.3  christos v_cmdsub_paren_tests_body() {
    527  1.3  christos 
    528  1.3  christos 	# Tests from:
    529  1.3  christos 	#	http://www.in-ulm.de/~mascheck/various/cmd-subst/
    530  1.3  christos 	# (slightly modified.)
    531  1.3  christos 
    532  1.3  christos 	atf_check -s exit:0 -o inline:'A.1\n' -e empty ${TEST_SH} -c \
    533  1.3  christos 		'echo $(
    534  1.3  christos 			case x in  x) echo A.1;; esac
    535  1.3  christos 		)'
    536  1.3  christos 
    537  1.3  christos 	atf_check -s exit:0 -o inline:'A.2\n' -e empty ${TEST_SH} -c \
    538  1.3  christos 		'echo $(
    539  1.3  christos 			case x in  x) echo A.2;; esac # comment
    540  1.3  christos 		)'
    541  1.3  christos 
    542  1.3  christos 	atf_check -s exit:0 -o inline:'A.3\n' -e empty ${TEST_SH} -c \
    543  1.3  christos 		'echo $(
    544  1.3  christos 			case x in (x) echo A.3;; esac
    545  1.3  christos 		)'
    546  1.3  christos 
    547  1.3  christos 	atf_check -s exit:0 -o inline:'A.4\n' -e empty ${TEST_SH} -c \
    548  1.3  christos 		'echo $(
    549  1.3  christos 			case x in (x) echo A.4;; esac # comment
    550  1.3  christos 		)'
    551  1.3  christos 
    552  1.3  christos 	atf_check -s exit:0 -o inline:'A.5\n' -e empty ${TEST_SH} -c \
    553  1.3  christos 		'echo $(
    554  1.3  christos 			case x in (x) echo A.5
    555  1.3  christos 			esac
    556  1.3  christos 		)'
    557  1.3  christos 
    558  1.3  christos 	atf_check -s exit:0 -o inline:'B: quoted )\n' -e empty ${TEST_SH} -c \
    559  1.3  christos 		'echo $(
    560  1.3  christos 			echo '\''B: quoted )'\''
    561  1.3  christos 		)'
    562  1.3  christos 
    563  1.3  christos 	atf_check -s exit:0 -o inline:'C: comment then closing paren\n' \
    564  1.3  christos 		-e empty ${TEST_SH} -c \
    565  1.3  christos 			'echo $(
    566  1.3  christos 				echo C: comment then closing paren # )
    567  1.3  christos 			)'
    568  1.3  christos 
    569  1.3  christos 	atf_check -s exit:0 -o inline:'D.1: here-doc with )\n' \
    570  1.3  christos 		-e empty ${TEST_SH} -c \
    571  1.3  christos 			'echo $(
    572  1.3  christos 				cat <<-\eof
    573  1.3  christos 				D.1: here-doc with )
    574  1.3  christos 				eof
    575  1.3  christos 			)'
    576  1.3  christos 
    577  1.3  christos 	# D.2 is a bogus test.
    578  1.3  christos 
    579  1.3  christos 	atf_check -s exit:0 -o inline:'D.3: here-doc with \()\n' \
    580  1.3  christos 		-e empty ${TEST_SH} -c \
    581  1.3  christos 			'echo $(
    582  1.3  christos 				cat <<-\eof
    583  1.3  christos 				D.3: here-doc with \()
    584  1.3  christos 				eof
    585  1.3  christos 			)'
    586  1.3  christos 
    587  1.3  christos 	atf_check -s exit:0 -e empty \
    588  1.3  christos 	  -o inline:'E: here-doc terminated with a parenthesis ("academic")\n' \
    589  1.3  christos 		${TEST_SH} -c \
    590  1.3  christos 		'echo $(
    591  1.3  christos 			cat <<-\)
    592  1.3  christos 			E: here-doc terminated with a parenthesis ("academic")
    593  1.3  christos 			)
    594  1.3  christos 		)'
    595  1.3  christos 
    596  1.3  christos 	atf_check -s exit:0 -e empty \
    597  1.3  christos -o inline:'F.1: here-doc embed with unbal single, back- or doublequote '\''\n' \
    598  1.3  christos 		${TEST_SH} -c \
    599  1.3  christos 		'echo $(
    600  1.3  christos 			cat <<-"eof"
    601  1.3  christos 		F.1: here-doc embed with unbal single, back- or doublequote '\''
    602  1.3  christos 			eof
    603  1.3  christos 		)'
    604  1.3  christos 	atf_check -s exit:0 -e empty \
    605  1.3  christos  -o inline:'F.2: here-doc embed with unbal single, back- or doublequote "\n' \
    606  1.3  christos 		${TEST_SH} -c \
    607  1.3  christos 		'echo $(
    608  1.3  christos 			cat <<-"eof"
    609  1.3  christos 		F.2: here-doc embed with unbal single, back- or doublequote "
    610  1.3  christos 			eof
    611  1.3  christos 		)'
    612  1.3  christos 	atf_check -s exit:0 -e empty \
    613  1.3  christos  -o inline:'F.3: here-doc embed with unbal single, back- or doublequote `\n' \
    614  1.3  christos 		${TEST_SH} -c \
    615  1.3  christos 		'echo $(
    616  1.3  christos 			cat <<-"eof"
    617  1.3  christos 		F.3: here-doc embed with unbal single, back- or doublequote `
    618  1.3  christos 			eof
    619  1.3  christos 		)'
    620  1.3  christos 
    621  1.3  christos 	atf_check -s exit:0 -e empty -o inline:'G: backslash at end of line\n' \
    622  1.3  christos 		${TEST_SH} -c \
    623  1.3  christos 			'echo $(
    624  1.3  christos 				echo G: backslash at end of line # \
    625  1.3  christos 			)'
    626  1.3  christos 
    627  1.3  christos 	atf_check -s exit:0 -e empty \
    628  1.3  christos 		-o inline:'H: empty command-substitution\n' \
    629  1.3  christos 		${TEST_SH} -c 'echo H: empty command-substitution $( )'
    630  1.3  christos }
    631  1.3  christos 
    632  1.1  christos atf_test_case z_absurd_heredoc_cmdsub_combos
    633  1.1  christos z_absurd_heredoc_cmdsub_combos_head() {
    634  1.1  christos 	atf_set "descr" "perverse and unusual cmd substitutions & more"
    635  1.1  christos }
    636  1.1  christos z_absurd_heredoc_cmdsub_combos_body() {
    637  1.2  christos 
    638  1.2  christos 	echo "Help!" > help
    639  1.2  christos 
    640  1.2  christos 	# This version works in NetBSD (& FreeBSD)'s sh (and most others)
    641  1.2  christos 	atf_check -s exit:0 -o inline:'Help!\nMe 2\n' -e empty ${TEST_SH} -c '
    642  1.2  christos 			cat <<- EOF
    643  1.2  christos 				$(
    644  1.2  christos 					cat <<- STOP
    645  1.2  christos 						$(
    646  1.2  christos 							cat `echo help`
    647  1.2  christos 						)
    648  1.2  christos 					STOP
    649  1.2  christos 				)
    650  1.2  christos 				$(
    651  1.2  christos 					cat <<- END 4<<-TRASH
    652  1.2  christos 						Me $(( 1 + 1 ))
    653  1.2  christos 					END
    654  1.2  christos 					This is unused noise!
    655  1.2  christos 					TRASH
    656  1.2  christos 				)
    657  1.2  christos 			EOF
    658  1.2  christos 		'
    659  1.2  christos 
    660  1.2  christos 	# atf_expect_fail "PR bin/50993 - heredoc parsing done incorrectly"
    661  1.2  christos 	atf_check -s exit:0 -o inline:'Help!\nMe 2\n' -e empty ${TEST_SH} -c '
    662  1.2  christos 			cat <<- EOF
    663  1.2  christos 				$(
    664  1.2  christos 					cat << STOP
    665  1.2  christos 						$(
    666  1.2  christos 							cat `echo help`
    667  1.2  christos 						)
    668  1.2  christos 					STOP
    669  1.2  christos 				)
    670  1.2  christos 				$(
    671  1.2  christos 					cat <<- END 4<<TRASH
    672  1.2  christos 						Me $(( 1 + 1 ))
    673  1.2  christos 					END
    674  1.2  christos 					This is unused noise!
    675  1.2  christos 					TRASH
    676  1.2  christos 				)
    677  1.2  christos 			EOF
    678  1.2  christos 		'
    679  1.1  christos }
    680  1.1  christos 
    681  1.1  christos atf_init_test_cases() {
    682  1.1  christos 	atf_add_test_case a_basic_cmdsub
    683  1.1  christos 	atf_add_test_case b_basic_backticks
    684  1.1  christos 	atf_add_test_case c_nested_cmdsub
    685  1.1  christos 	atf_add_test_case d_nested_backticks
    686  1.1  christos 	atf_add_test_case e_perverse_mixing
    687  1.1  christos 	atf_add_test_case f_redirect_in_cmdsub
    688  1.1  christos 	atf_add_test_case g_redirect_in_backticks
    689  1.1  christos 	atf_add_test_case h_vars_in_cmdsub
    690  1.1  christos 	atf_add_test_case i_vars_in_backticks
    691  1.1  christos 	atf_add_test_case j_cmdsub_in_varexpand
    692  1.1  christos 	atf_add_test_case k_backticks_in_varexpand
    693  1.1  christos 	atf_add_test_case l_arithmetic_in_cmdsub
    694  1.1  christos 	atf_add_test_case m_arithmetic_in_backticks
    695  1.1  christos 	atf_add_test_case n_cmdsub_in_arithmetic
    696  1.1  christos 	atf_add_test_case o_backticks_in_arithmetic
    697  1.1  christos 	atf_add_test_case p_cmdsub_in_heredoc
    698  1.1  christos 	atf_add_test_case q_backticks_in_heredoc
    699  1.1  christos 	atf_add_test_case r_heredoc_in_cmdsub
    700  1.1  christos 	atf_add_test_case s_heredoc_in_backticks
    701  1.1  christos 	atf_add_test_case t_nested_cmdsubs_in_heredoc
    702  1.1  christos 	atf_add_test_case u_nested_backticks_in_heredoc
    703  1.3  christos 	atf_add_test_case v_cmdsub_paren_tests
    704  1.1  christos 	atf_add_test_case z_absurd_heredoc_cmdsub_combos
    705  1.1  christos }
    706