for循环语法

for循环语法

为什么

for i in {1..5}; do x="${i}" echo "$x"; done

不输出

1
2
3
4
5

这样做的正确方法是什么?

(已测试for i in {1..5}; do x=$(i) echo "$x"; done

-bash: i: 未找到命令

和别的)

答案1

按要求回答您的问题

为什么不for i in {1..5}; do x="${i}" echo "$x"; done输出1、、、、?2345

原因与执行期间评估操作的顺序有关。看看这个命令

x="${i}" echo "$x"

这是做什么的

  1. 用变量的值替换变量
  2. 为变量分配临时值x
  3. 执行命令

所以你得到

  1. x=1 echo ""(或x=2 echo "",等等)
  2. 在此命令的持续时间内,x设置为值1
  3. 执行命令:echo ""

您可能认为该命令是两条指令:为 赋值x,输出其值。但在 shell 语法中,您编写的代码是完全合法的,因此 shell 会毫无异议地执行它。

答案2

您要求回答两个问题:

  1. 您要求解释为什么当前代码没有产生预期的输出。

  2. 您询问了编写代码的正确方法,以便它确实产生预期的输出。

查看您的代码,我可以看到两种可能的解释来解释为什么您以这种方式编写代码:

  1. 可能会有一些轻微的混乱for循环的语法

  2. 在所谓的评估顺序中可能存在一些轻微的混乱简单的命令

for循环语法

在第一种情况下,我会说你在变量赋值后缺少一个分号。如果您想将 for 循环写在一行上,那么您需要在循环体中的每个命令后面放置一个分号。试试这个:

for i in {1..5}; do x="${i}"; echo "$x"; done

另一种选择是使用多行语法编写 for 循环,并用换行符代替分号:

for i in {1..5}
do
x="${i}"
echo "${x}"
done

您还可以混合搭配分号和换行符,例如:

for i in {1..5}; do
x="${i}"; echo "${x}"
done

评估简单命令

在第二种情况下,我想说您可能假设命令序言中的变量赋值(即赋值x="$i")发生在命令主体中的变量扩展(即${x}in的扩展echo "${x}")之前。但事实并非如此。为了验证这一点,我们可以参考页面简单的命令扩展在 Bash 手册中或关于简单命令的小节在里面POSIX规范。这两篇参考文献都包含以下段落:

“简单命令”是一系列可选的变量分配和重定向,可以任意顺序,可选地后跟单词和重定向,并由控制运算符终止。

当需要执行给定的简单命令时(即,当任何条件结构,例如 AND-OR 列表或案件语句没有绕过简单命令),以下扩展、赋值和重定向都应从命令文本的开头到结尾执行:

  1. 根据以下规则被识别为变量赋值或重定向的单词Shell 语法规则保存以供步骤 3 和 4 中的处理。

  2. 非变量赋值或重定向的词应扩展。如果扩展后仍有任何字段,则第一个字段应被视为命令名称,其余字段是命令的参数。

  3. 重定向应按中所述执行重定向

  4. 每个变量赋值都应在赋值之前进行扩展,以进行波形符扩展、参数扩展、命令替换、算术扩展和引号删除。

请注意,步骤 2 是命令中发生变量扩展的地方,但步骤 1 告诉我们变量赋值将保存到步骤 3 和 4。因此,表达式echo "${x}"将扩展至echo ""赋值x="${i}"发生之前。这解释了为什么您得到空输出。

有关此主题的进一步讨论,请参阅以下帖子:

答案3

在 中,使用, Bourne 运算符的zsh第三种${var::=value}形式,其中赋值是无条件的(而不是仅当 var 未设置/为空时)。${var=value}${var:=value}

for i in {1..5}; do echo ${x::=$i}; done

或者:

for i ({1..5}) echo ${x::=$i}

bash

set -o posix # so the value of x remains after eval returns
for i in {1..5}; do x=$i eval 'echo "$x"'; done

也就是说,您需要$x在评估包含其扩展的代码时进行设置。

对于像这里这样的十进制整数值,您还可以执行以下操作:

for i in {1..5}; do echo "$((x = i))"; done

或者,您始终可以${var:=value}在设置x为空字符串后使用 Bourne 运算符。

for i in {1..5}; do x=; echo "${x:=$i}"; done

相关内容