Disclaimer:
From the discussion above, I implemented a solution. This is not, by far, the one I dreamed of, because of the verbosity of ${args_array[1]}, compared to $1. Makes the source less readable. So improvements, or a better solution are still welcome.
Source:
Tested, something like this:
#!/bin/bash
#########################
# DEBUG
#########################
# set -x
PS4='${xchars:-+} ${BASH_SOURCE}:${LINENO} (${FUNCNAME[@]}) + ' # full stack
#########################
# INITIAL ARGS FOR TEST
#########################
set -- a b c d e f g h
#########################
# UTILITIES
#########################
args_array=( "$@" ) # script args here
args_shift() # Usage readability OK, replaces shift <n>
{
typeset n=${1:-1}
echo "args_shift $1 in ${FUNCNAME[1]} -- ${args_array[@]}"
args_array=( "${args_array[@]:$n}" ) # ${1:-1} unsupported in this context
echo "args_shift $1 in ${FUNCNAME[1]} ++ ${args_array[@]}"
}
args_set() # Usage readability OK, replaces set -- <args>
{
echo "args_set $@ in ${FUNCNAME[1]} -- ${args_array[@]}"
args_array=( "$@" ) # function args here
echo "args_set $@ in ${FUNCNAME[1]} ++ ${args_array[@]}"
}
# Usage
# search/replace OK, and good readability afterward
# shift <n> ---> args_shift <n>
# set -- <args> ---> args_set <args>
# search/replace OK, but bad readability afterward, and refactoring--
# $@ ---> ${args_array[@]}
# $# ---> ${#args_array[@]}
# $1 ---> ${args_array[0]} !!! 1 -> 0
# $2 ---> ${args_array[1]} !!! 2 -> 1
# etc
#########################
# TEST
#########################
f()
{
args_shift
}
g()
{
args_set A B C D
}
# main
echo "main -- ${args_array[@]}"
f
args_shift 2
f
g
args_shift
f
echo "main ++ ${args_array[@]}"
Output:
main -- a b c d e f g h
args_shift in f -- a b c d e f g h
args_shift in f ++ b c d e f g h
args_shift 2 in main -- b c d e f g h
args_shift 2 in main ++ d e f g h
args_shift in f -- d e f g h
args_shift in f ++ e f g h
args_set A B C D in g -- e f g h
args_set A B C D in g ++ A B C D
args_shift in main -- A B C D
args_shift in main ++ B C D
args_shift in f -- B C D
args_shift in f ++ C D
main ++ C D
Remarks:
- Works but not the most readable solution, and refactoring not so light, because there are several forms of usage to take into consideration: $1, more or less ${1[:/][^}]} or ${!1[:/][^}]} etc, while avoiding those in function, awk, perl etc.
- For some, as variable names are case sensitive in bash and, I think, more or less seldom used, on could use A or _A instead of args_array but, to my taste, ${A[1]} or so is even less readable in a long source than ${args_array[1]}.
My situation:
There are at least 616 occurrences to take care of... carefully (some are in functions, awk or perl scripts etc)
for s in shift 'set --' '$@' '${@' '$*' '${*' '$1' '${1' '$2' '${2' '$3' '${3' '$4' '${4' '$5' '${5'; do
printf '%-10s: %d\n' "$s " "$(fgrep $s <script>|wc -l)"
done # |awk '{sum+=$NF};END{print sum}'
shift : 44
set -- : 189
$@ : 39
${@ : 2
$* : 7
${* : 0
$1 : 182
${1 : 79
$2 : 48
${2 : 3
$3 : 15
${3 : 0
$4 : 8
${4 : 0
$5 : 0
${5 : 0
myfunc "$@"
.