You can't without A
making its positional parameters available to B
one way or another. Could be by passing them along:
A() {
B "$@"
}
B() {
[ "$#" -eq 0 ] || printf '<%s>\n' "$@"
}
Or storing them in an array:
A() {
A_args=( "$@" )
B
}
B() {
[ "${#A_args[@]}" -eq 0 ] || printf '<%s>\n' "${A_args[@]}"
}
As bash, like ash/ksh88/zsh (but unlike ksh93 or zsh's private
variables) does dynamic scoping for its local variables, you could even make that A_args
variable local
to A
and it would still be available in the functions that A
calls.
bash
lets you access variables of its parent scope even when they're shadowed by local variables in the current scope by exploiting a current bug of its unset
builtin (which under some conditions doesn't unset but reveal the variable from the parent scope), but you can't access the positional parameters from the parent scope that way because in bash (contrary to zsh
/rc
/fish
...), positional parameters cannot be mapped to array variables as bash array design is shaped after that of the Korn shell where arrays are not really arrays.
If you want some code to be able to access or modify (via shift
or set
) the function's positional parameters or local options, or return
from the function, you need that code to run in the scope of that function, so that cannot be in a separate function.
You could use aliases (which are the shell equivalent of C pre-processor macros, except they can't take arguments) or eval
though.
Beware though that:
- in the bash shell and when not in POSIX mode, alias expansion is disabled by default so you'll need
shopt -s expand_aliases
.
- the alias must exists before the code of the function is read, and it is expanded inside the code of the function.
So you could do:
[ -z "$BASH_VERSION" ] || shopt -s expand_aliases # work around for bash
alias B='{
[ "$#" -eq 0 || printf "<%s>\n" "$@"
shift
}'
A() {
echo "$#"
B
echo "$#"
}
A a b c
Or:
B='
[ "$#" -eq 0 || printf "<%s>\n" "$@"
shift
'
A() {
echo "$#"
eval "$B"
echo "$#"
}
A a b c
getopts
alike function without pass "A"'s arguments but knowing what "A" has.