我有一个while循环,它从下面的文本文件中读取:
hashicorp/aws/4.27.0
hashicorp/aws/4.26.0
hashicorp/aws/4.11.0
...从中读取的while循环如下:
while read -r owner provider version; do \
IFS=/
echo $owner
done < providers.txt
output:
hashicorp aws 4.27.0
hashicorp
hashicorp出于某种原因,它似乎没有在第一行使用集合IFS。
但是,通过移动IFS,我可以得到正确的结果:
while IFS=/ read -r owner provider version; do \
echo $owner
done < providers.txt
output:
hashicorp
hashicorp
hashicorp但是我不明白为什么在第一个例子中它没有正确地使用IFS,因为IFS=/仍然被设置在echo语句之前。谁能解释一下吗?
发布于 2022-08-23 17:36:17
这是因为第一个版本直到第一行被读取和拆分之后才会将IFS设置为"/“。设置变量的时间和地点决定了变量的影响,理解差异很重要。
遍历被执行的内容可能会有帮助。当脚本到达while循环时,它首先执行while子句:
while read -r owner provider version...which从文件中读取第一行。由于IFS在此时仍然有其默认值(空格+选项卡+换行符),因此该行将根据该值进行拆分(即根本不拆分),因此整行都在owner变量中。
接下来,由于while子句成功,while循环的主体将执行:
IFS=/
echo $owner...this设置IFS,然后设置echoes $owner。由于$owner不是双引号,而且运行IFS的时间设置为"/“时,该值将得到基于"/”的分词,因此有效执行的是echo "hashicorp" "aws" "4.27.0",哪种类型的字符具有将变量中的"/“字符转换为空格的效果。这种奇怪的解析效果就是为什么您应该使用almost always double-quote variable references。
接下来,循环再次运行。这一次,IFS被设置为"/",因此read命令将在此基础上拆分行,从这一点开始,它将按照您的预期运行。
现在,将其与第二个版本进行比较:
while IFS=/ read -r owner provider version; do在这里,分配给IFS的不是单独的命令,而是read命令的前缀。这意味着它总是应用于read命令,也使得它只应用于read命令。因此,它在每次运行read时都会应用,而且以后也不会影响其他事情,比如任何未引用的变量引用。将IFS设置为非标准值可能会造成麻烦,并且将其限制在这样的单个命令上是防止它在以后引起麻烦的好方法。
教训: 1)双引号变量,2)在可能的情况下将IFS设置为特定命令的前缀(如果不可能,在需要影响的命令之前将其设置,然后在以后尽快将其设置为正常)。
发布于 2022-08-23 16:23:49
bash中的IFS变量控制单词如何被shell分割。默认情况下,这是空格、选项卡和换行符。设置IFS的原因是,当在read调用中发生分词时,单词由/而不是空格分割。这个变量与回显调用无关,因为owner变量只包含单词hashicorp。
https://stackoverflow.com/questions/73461757
复制相似问题