Answers:
首先,请注意,$@不带引号是没有意义的,因此不应使用。$@只能在引号("$@")和列表上下文中使用。
for i in "$@" 符合列表上下文的条件,但是在这里,为了遍历位置参数,规范,最可移植且更简单的形式是:
for i
do something with "$i"
done
现在,要循环从第二个元素开始的元素,规范和最可移植的方法是使用shift:
first_arg=$1
shift # short for shift 1
for i
do something with "$i"
done
之后shift,以前的内容$1已从列表中删除(但我们已经将其保存在中$first_arg),$2现在的内容现在在中$1。位置参数已向左移动 1位置(用于shift 2移动2 ...)。因此,基本上,我们的循环从过去的第二个参数循环到最后一个。
使用bash(和zsh和ksh93,仅此而已),另一种方法是:
for i in "${@:2}"
do something with "$i"
done
但请注意,它不是标准sh语法,因此不应在以开头的脚本中使用#! /bin/sh -。
在zsh或中yash,您还可以执行以下操作:
for i in "${@[3,-3]}"
do something with "$i"
done
从第3个参数循环到第3个最后一个参数。
在中zsh,$@也称为$argv数组。因此,要从数组的开头或结尾弹出元素,您还可以执行以下操作:
argv[1,3]=() # remove the first 3 elements
argv[-3,-1]=()
(shift也可以被写1=()在zsh)
在中bash,您只能分配$@带有set内置元素的元素,因此要从末尾弹出3个元素,就像这样:
set -- "${@:1:$#-3}"
并从第3个循环到最后一个第3个:
for i in "${@:3:$#-5}"
do something with "$i"
done
POSIXly,要弹出的最后3个元素"$@",您需要使用循环:
n=$(($# - 3))
for arg do
[ "$n" -gt 0 ] && set -- "$@" "$arg"
shift
n=$((n - 1))
done
在bash中,您还可以使用显式索引编写该循环:
for ((i=2; i<=$#; ++i)); do
process "${!i}"
done
这将迭代从第二个参数到最后一个参数的所有参数。如果您想排除最后一个参数,只需执行以下操作
for ((i=1; i<=$#-1; ++i)); do
process "${!i}"
done
如果只想接受其他所有参数,则将其写为
for ((i=1; i<=$#; i+=2)); do
process "${!i}"
done
其背后的故事是内置函数的算术版本,结合了参数计数和变量indirect。for$#${…}
一个不错的应用程序是您可以使用它来确定循环内给定选项是否将其后的参数作为值。如果是这样,则增加i(例如写入: $((++i)))以消耗下一个值,并在迭代过程中跳过它。
for ((i=2; i<=$#; i++)); do something with "${!i}"; done