I know that it is possible to reverse "$@"
using an array:
arr=( "$@" )
And using this answer, reverse the array.
But that requires a shell that has arrays.
It is also possible using tac
:
set -- $( printf '%s\n' "$@" | tac )
But that breaks if the parameters have spaces, tabs or newlines (assuming the default value of $IFS
) or contain wildcard characters (unless globbing is disabled beforehand) and removes empty elements, and requires the GNU tac
command (using tail -r
is slightly more portable outside of GNU systems but with some implementations fails on large input).
Is there a way to reverse shell positional arguments portably, without using an array, and that works even if arguments contain whitespaces or newlines or wildcards or are possibly empty?
Best Answer
Portably, no arrays required (only positional parameters) and works with spaces and newlines:
Example:
The value of
flag
controls the expansion of${flag-"$@"}
. Whenflag
is set, it expands to the value offlag
(even if it is empty). So, whenflag
isflag=''
,${flag....}
expands to an empty value and it gets removed by the shell as it is unquoted. When theflag
gets unset, the value of${flag-"$@"}
gets expanded to the value at the right side of the-
, that's the expansion of"$@"
, so it becomes all the positional arguments (quoted, no empty value will get erased). Additionally, the variableflag
ends up erased (unset) not affecting following code.