假设我有以下内容:
for i in $@; do
echo ${i+1}
done
我在 shell 上运行它$ test.sh 3 5 8 4
,它输出1 1 1 1
为什么 ${i+1} 不起作用?我正在尝试访问命令行参数列表的下一个参数。
答案1
shell 中的每个字符可能都有特殊的含义。
该代码${i+1}
并不意味着“i 加 1”。
要了解其含义,请执行以下命令:
LESS=+/'\{parameter\:\+word\}' man bash
并阅读:
${parameter:+word}
使用替代值。如果参数为空或未设置,则不会替换任何内容,否则将替换单词的扩展。
上面一点:
省略冒号会导致仅测试未设置的参数。
由于$i
循环设置了一个值,for i in $@;
“替代值”被替换并被1
打印。
如果要将参数值加 1,请执行以下操作:
for i
do echo "$((i+1))"
done
不需要in "$@"
(并习惯引用所有扩展)。
$ ./test.sh 3 5 8 4
4
6
9
5
接下来的论证。
但这也不是“下一个论点”。核心问题在于您的循环,您在循环中使用参数的值,而不是参数的索引。您需要循环遍历参数的索引,而不是每个参数的i
值。i
就像是:
for (( i=1; i<=$#; i++)); do
echo "${i}"
done
这将打印一个索引,如下所示:
$ ./test.sh 3 5 8 4
1
2
3
4
间接
我们如何访问位置$i
? 处的参数?: 使用间接:
for (( i=1; i<=$#; i++)); do
echo "${!i}"
done
看到简单的!
添加了吗?
现在它运行起来是这样的:
$ ./test.sh 3 5 8 4
3
5
8
4
最终解决方案。
要打印当前参数和下一个参数,请使用以下命令:
for (( i=1; i<=$#; i++)); do
j=$((i+1))
echo "${!i} ${!j}"
done
不,没有比计算变量中的值更简单的方法了$j
。
$ ./test.sh 3 5 8 4
3 5
5 8
8 4
4
这也适用于文本:
$ ./test.sh sa jwe yqs ldfgt
sa jwe
jwe yqs
yqs ldfgt
ldfgt
答案2
在您的示例代码中,我是值,而不是索引。
您需要使用感叹号来将变量值用作变量。
如果不定义另一个变量,我就无法让 (i+1) 工作。也许有人可以给出优化的提示。
check () {
for i in $(seq $#); do
let j=i+1
echo "$i: i=${!i} i+1=${!j}"
done
}
check a b c
1: i=a i+1=b
2: i=b i+1=c
3: i=c i+1=
答案3
首先请注意,${i+1}
是一种参数扩展模式,这意味着如果参数i
未设置或为 null,它将被 的扩展替换1
,这当然只会导致1
。因此,您将在输出中得到全 1。
您需要使用算术运算符,而不是参数扩展。
例如:
% check () { for i in "$@"; do echo $((i+1)); done ;}
% check 2 4 5 6
3
5
6
7
答案4
扩展于user79743的上面回答:
假设我们想要一个参数采用类似--mode delete
or 的值--mode list
。
当 时${!i} == "--mode"
,我们想要读取 的值下列的索引 (j
或i+1
) 并保留它供以后使用。考虑到在下一个循环迭代中,我们最终将进行i+1
第二次检查(j
在上一个循环上,在i
当前循环上)。
我发现它i
是可变的,所以我们可以将它增加 1,这意味着下一个循环迭代将是i+2
,可以这么说。
我确实想说,一般来说,在迭代时改变一个值是不明智的。这种方法对我来说确实有效。我确信可能有几种(更好的)方法可以做到这一点。
不增加i
.有些索引会被检查多次。
# $ ./test.sh --mode delete 3 5 8 4
# [1]: --mode [2]: delete
# [2]: delete # <-- index [2] is inspected twice
# [3]: 3
# [4]: 5
# [5]: 8
# [6]: 4
for (( i=1; i<=$#; i++)); do
if [[ ${!i} == "--mode" ]]; then
j=$((i+1))
MODE=${!j} # retain for later
echo "[$i]: ${!i} [$j]: ${!j}"
else
echo "[$i]: ${!i}"
fi
done
随着递增i
.每个索引只检查一次。
# $ ./test.sh --mode delete 3 5 8 4
# [1]: --mode [2]: delete
# [3]: 3
# [4]: 5
# [5]: 8
# [6]: 4
for (( i=1; i<=$#; i++)); do
if [[ ${!i} == "--mode" ]]; then
j=$((i+1))
MODE=${!j} # retain for later
echo "[$i]: ${!i} [$j]: ${!j}"
i=$i+1 # <-- incrementing the index
else
echo "[$i]: ${!i}"
fi
done