# now some funky ones.
# ${V+word} "if V unset, then substitute nothing, else substitute word"
# ${V:+word} "if V unset or '', then substitute nothing, else substitute word"
-# bash doesn't accept ${#+}. ash prints 0 (not $#).
+# bash doesn't accept ${#+}. ash prints 0 (not $#): "len of $+"
echo _${#+}_ _${#:+}_
# Forms with non-empty word work as expected in both ash and bash.
echo _${#+z}_ _${#:+z}_
--- /dev/null
+# ${#c} for any single char c means "length of $c", including all special vars
+
+false
+echo One:${#?}
+(exit 10)
+echo Two:${#?}
+(exit 100)
+echo Three:${#?}
+
+echo
+echo One:${##}
+set -- 1 2 3 4 5 6 7 8 9 0
+echo Two:${##}
+set -- 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 \
+ 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 \
+ 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 \
+ 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
+echo Three:${##}
+
+echo
+v=$$
+test "${#v}" = "${#$}"
+echo 'Ok ${#$}:' $?
+
+echo
+sleep 0 &
+v=$!
+test "${#v}" = "${#!}"
+echo 'Ok ${#!}:' $?
+
+# TODO: ${#-} ${#_}
case '@': /* args */
goto make_one_char_var;
case '{': {
+ char len_single_ch;
+
o_addchr(dest, SPECIAL_VAR_SYMBOL);
ch = i_getch(input); /* eat '{' */
return 0;
}
nommu_addchr(as_string, ch);
+ len_single_ch = ch;
ch |= quote_mask;
/* It's possible to just call add_till_closing_bracket() at this point.
/* handle parameter expansions
* http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02
*/
- if (!strchr(VAR_SUBST_OPS, ch)) /* ${var<bad_char>... */
- goto bad_dollar_syntax;
-
+ if (!strchr(VAR_SUBST_OPS, ch)) { /* ${var<bad_char>... */
+ if (len_single_ch != '#'
+ /*|| !strchr(SPECIAL_VARS_STR, ch) - disallow errors like ${#+} ? */
+ || i_peek(input) != '}'
+ ) {
+ goto bad_dollar_syntax;
+ }
+ /* else: it's "length of C" ${#C} op,
+ * where C is a single char
+ * special var name, e.g. ${#!}.
+ */
+ }
/* Eat everything until closing '}' (or ':') */
end_ch = '}';
if (BASH_SUBSTR
}
break;
}
+ len_single_ch = 0; /* it can't be ${#C} op */
}
o_addchr(dest, SPECIAL_VAR_SYMBOL);
break;
first_char = arg[0] = arg0 & 0x7f;
exp_op = 0;
- if (first_char == '#' && arg[1] /* ${#... but not ${#} */
- && (!exp_saveptr /* and (not ${#<op_char>...} */
- || (arg[1] == '?' && arg[2] == '\0') /* or ${#?} - "len of $?") */
- )
+ if (first_char == '#' && arg[1] /* ${#...} but not ${#} */
+ && (!exp_saveptr /* and ( not(${#<op_char>...}) */
+ || (arg[2] == '\0' && strchr(SPECIAL_VARS_STR, arg[1])) /* or ${#C} "len of $C" ) */
+ ) /* NB: skipping ^^^specvar check mishandles ${#::2} */
) {
/* It must be length operator: ${#var} */
var++;
# now some funky ones.
# ${V+word} "if V unset, then substitute nothing, else substitute word"
# ${V:+word} "if V unset or '', then substitute nothing, else substitute word"
-# bash doesn't accept ${#+}. ash prints 0 (not $#).
+# bash doesn't accept ${#+}. ash prints 0 (not $#): "len of $+"
echo _${#+}_ _${#:+}_
# Forms with non-empty word work as expected in both ash and bash.
echo _${#+z}_ _${#:+z}_
--- /dev/null
+# ${#c} for any single char c means "length of $c", including all special vars
+
+false
+echo One:${#?}
+(exit 10)
+echo Two:${#?}
+(exit 100)
+echo Three:${#?}
+
+echo
+echo One:${##}
+set -- 1 2 3 4 5 6 7 8 9 0
+echo Two:${##}
+set -- 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 \
+ 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 \
+ 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 \
+ 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
+echo Three:${##}
+
+echo
+v=$$
+test "${#v}" = "${#$}"
+echo 'Ok ${#$}:' $?
+
+echo
+sleep 0 &
+v=$!
+test "${#v}" = "${#!}"
+echo 'Ok ${#!}:' $?
+
+# TODO: ${#-} ${#_}