First, note that $@
without quotes makes no sense and should not be used. $@
should only be used quoted ("$@"
) and in list contexts.
for i in "$@"
qualifies as a list context, but here, to loop over the positional parameters, the canonical, most portable and simpler form is:
for i
do something with "$i"
done
Now, to loop over the elements starting from the second one, the canonical and most portable way is to use shift
:
first_arg=$1
shift # short for shift 1
for i
do something with "$i"
done
After shift
, what used to be $1
has been removed from the list (but we've saved it in $first_arg
) and what used to be in $2
is now in $1
. The positional parameters have been shifted 1
position to the left (use shift 2
to shift by 2...). So basically, our loop is looping from what used to be the second argument to the last.
With bash
(and zsh
and ksh93
, but that's it), an alternative is to do:
for i in "${@:2}"
do something with "$i"
done
But note that it's not standard sh
syntax so should not be used in a script that starts with #! /bin/sh -
.
In zsh
or yash
, you can also do:
for i in "${@[3,-3]}"
do something with "$i"
done
to loop from the 3rd to the 3rd last argument.
In zsh
, $@
is also known as the $argv
array. So to pop elements from the beginning or end of the arrays, you can also do:
argv[1,3]=() # remove the first 3 elements
argv[-3,-1]=()
(shift
can also be written 1=()
in zsh
)
In bash
, you can only assign to the $@
elements with the set
builtin, so to pop 3 elements off the end, that would be something like:
set -- "${@:1:$#-3}"
And to loop from the 3rd to the 3rd last:
for i in "${@:3:$#-5}"
do something with "$i"
done
POSIXly, to pop the last 3 elements of "$@"
, you'd need to use a loop:
n=$(($# - 3))
for arg do
[ "$n" -gt 0 ] && set -- "$@" "$arg"
shift
n=$((n - 1))
done
for ((i=2; i<=$#; i++)); do something with "${!i}"; done
– glenn jackman Aug 27 '15 at 20:24$@
without quotes makes no sense and should not be used? – Martin Vegter Jul 25 '21 at 05:29"$@"
means quote every string in$*
, so forcmd "a = b" c d
, insidecmd
,"$@"
would have three elements,a = b
,b
, andc
, whereas$@
would be no different than$*
, producing 5 elements:a
,=
,b
,c
, andd
. – Jeff Learman Jan 28 '22 at 16:56