Is this portable?
filter() {
set -- CUT "$@"
for x; do
if test "$x" = CUT; then
set -- # ignore args upto here
else # perhaps more filtering
set -- "$@" "$x"
fi
done
printf "'%s' " "$@"; echo
}
filter "$@"
I.e. can I change "$@"
while iterating over it? Does the for
compound duplicate the implicit array?
filter 1 2 CUT 3
Seems to work in dash
, ash
, busybox sh
.
Yes, POSIX does allow that. It can be inferred from the section titled The for Loop (quoted below, emphasis mine) that the loop keeps its own private copy of the list of items it is to iterate over, and that changes made to the shell execution environment while the loop is performed will not have any effect on said copy.
for name [ in [word ... ]] do compound-list done
First, the list of words following
in
shall be expanded to generate a list of items. Then, the variablename
shall be set to each item, in turn, and thecompound-list
executed each time. Omitting:in word...
shall be equivalent to:
in "$@"
In other words, it is guaranteed that the loop in your program iterates over the initial list of positional parameters because the implied expansion of "$@"
precedes set --
and set -- "$@" "$x"
.