在 Bash 中迭代命令行参数

在 Bash 中迭代命令行参数

有人可以解释这两个代码块之间的区别吗?我认为块 #2 会输出与块 #1 相同的输出,但事实并非如此。有人可以解释为什么吗?

# ./arguments.sh hello my name is X

区块 #1

for i
do
    echo $i
done

输出:

hello
my
name
is
X

区块 #2

args=$#
for (( i=1; i<=$args; i+=1 ))
do
    echo $i
done

输出:

1
2
3
4
5

答案1

第一个块(隐式)迭代命令行参数"$@"

for i in "$@"    # same as your "for i"
do
    echo "$i"
done

第二个块显式地迭代参数的数量,并打印索引:

args=$#                          # number of command line args
for (( i=1; i<=$args; i+=1 ))    # loop from 1 to N (where N is number of args)
do
    echo $i
done

根据您的示例,假设$#为 5,则该$i变量将采用值1, 2, 3, 4, 5

正如另一个(现已删除)答案中指出的,您可以按索引引用命令行参数,如下所示:

args=$#
for (( i=1; i<=$args; i++ ))
do
    echo "$i - ${!i}"
done

答案2

罗艾玛的回答回答您实际提出的问题:

问:这两个代码块有什么区别?为什么他们给出不同的输出?

A:第一个循环是迭代命令行参数;第二个是迭代参数数字(指数)。

...尽管我认为您在另外六到八分钟内就会自己弄清楚这一点 - 这是显而易见的。您可能希望第二个程序执行类似的操作

echo $$i                                        # This doesn't do what you want.

显示由存储在变量中的数字索引的参数i(并引用为 $i)。正如评论中所指出的,这并不能达到您想要的效果。 (它做一点事;我鼓励你去尝试并找出答案什么确实如此。)但这接近于确实有效的东西:

eval echo \$$i                                  # Don't do this.

或者,等价地,

eval echo '$'"$i"                               # Don't do this.

这些命令

  • i获取(数字 1、2、3、... 之一)的值
  • $在其前面粘贴一个,形成$1, $2,$3等。
  • 使用eval命令说:“采用我刚刚构建的命令行,并且评估就像我打字一样。

这样就会有执行的效果

echo $1
echo $2
echo $3

但是,正如评论所建议的,您应该尽量避免这种情况。  eval如果输入不是普通单词,则可能会很危险。站内搜索;你会发现很多对此的解释。

但是有一种相当安全的方法可以让第二个程序执行与第一个程序相同的操作:更改

echo $i

echo ${!i}

好的,首先,${i}与 几乎相同$i。给!你一个类似于命令的效果eval- ${!x}查找x(ie, $xor ${x}) 的值并使用作为要查找的变量的名称。因此,如果x=foo,则${!x}与 相同$foo。上面的代码对 执行同样的操作i,获取名称为 的值的参数i

顺便说一句,您应该始终引用对 shell 变量的所有引用(例如,"$i""$#""$args"和) "${i}""${!i}"除非您有充分的理由不这样做,并且您确信您知道自己在做什么。

相关内容