如何访问bash中命令行参数的下一个参数?

如何访问bash中命令行参数的下一个参数?

假设我有以下内容:

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 deleteor 的值--mode list

当 时${!i} == "--mode",我们想要读取 的值下列的索引 (ji+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

相关内容