我需要编写一个以这种方式运行的 shell 脚本:
./myscript arg1 arg2_1 arg2_2 arg2_3 ....... arg2_#
脚本中有一个 for 循环
for i in $@
然而,据我所知,$@ 包括 $1 到 $($#-1)。但对于我的程序来说,$1 与 $2 $3 $4 等明显不同。我想从 $2 循环到最后...我该如何实现这一点?谢谢你:)
答案1
首先,请注意,$@
不带引号是没有意义的,不应使用。$@
只能在引用 ( "$@"
) 和列表上下文中使用。
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
从第三个参数循环到第三个最后一个参数。
在 中zsh
,$@
也称为$argv
数组。因此,要从数组的开头或结尾弹出元素,您还可以执行以下操作:
argv[1,3]=() # remove the first 3 elements
argv[-3,-1]=()
(shift
也可以1=()
写成zsh
)
在 中bash
,您只能使用内置元素分配给元素$@
,set
因此要从末尾弹出 3 个元素,类似于:
set -- "${@:1:$#-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
答案2
我想你想要shift
内置的。它重命名$2
为$1
、$3
to$2
等。
像这样:
shift
for i in "$@"; do
echo $i
done
答案3
总是有穴居人的方法:
first=1
for i
do
if [ "$first" ]
then
first=
continue
fi
something with "$i"
done
这会$@
保持完整(以防您以后想使用它),并且简单地循环每个参数,但不处理第一个参数。
答案4
在 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
这背后的故事是算术的版本for
内置,结合参数计数$#
和变量间接${…}
。
一个很好的应用是,您可以使用它来在循环内决定给定选项是否将其后面的参数作为值。如果是,则增加i
(例如写入: $((++i))
)以消耗下一个值并在迭代期间跳过它。