unset myVariable i;
while [ -z "$i" ]; do
read myVariable;
echo "myVariable : '$myVariable'";
i=foo;
done;
echo "myVariable : '$myVariable'"
(unset
允许重播命令)
按任意键 + ENTER,您将得到:
myVariable : '[what you typed]'
myVariable : '[what you typed]'
的值myVariable
存在于while
循环之外。现在尝试:
tmpFile=$(mktemp);
echo -e 'foo\nbar\nbaz' >> "$tmpFile"
while read myVariable; do
otherVariable=whatever;
echo "myVariable : '$myVariable', otherVariable : '$otherVariable'";
done < "$tmpFile";
echo "myVariable : '$myVariable', otherVariable : '$otherVariable'";
rm "$tmpFile"
你会得到 :
myVariable : 'foo', otherVariable : 'whatever'
myVariable : 'bar', otherVariable : 'whatever'
myVariable : 'baz', otherVariable : 'whatever'
myVariable : '', otherVariable : 'whatever'
myVariable
当离开循环时,的值就会丢失。
为什么会有不同的行为?有我不知道的范围技巧吗?
注意:运行 GNU bash,版本 4.4.12(1)-release (x86_64-pc-linux-gnu)
答案1
while read myVariable; do
myVariable
当离开循环时,的值就会丢失。
不,myVariable
具有从上次获得的值read
。该脚本从文件中读取,直到到达最后一个换行符之后的位置。之后,最终read
调用不会从文件中获取任何内容,myVariable
相应地设置为空字符串,并以错误值退出,因为它没有看到分隔符(换行符)。然后循环结束。
read
如果最后一个换行符后面有不完整的行,您可以从最终得到一个非空值:
$ printf 'abc\ndef\nxxx' |
{ while read a; do echo "got: $a"; done; echo "end: $a"; }
got: abc
got: def
end: xxx
或者用于while read a || [ "$a" ]; do ...
处理循环体内的最后一行片段。
答案2
因为您正在通过管道连接到 while 循环,所以会创建一个子 shell 来运行 while 循环。现在,这个子进程拥有自己的环境副本,并且无法将任何变量传递回其父进程(就像在任何 UNIX 进程中一样)。
在这种情况下,done < "$tmpFile"
重定向会强制 bash 生成一个子 shell(对于管道)。
引自bash 变量作用域在堆栈溢出上。
答案3
您的第二个示例使用while
具有重定向输入的循环。
它读取 using< "$tmpFile"
并且许多 shell 为这种情况创建了一个子 shell。您可以尝试使用 运行此脚本ksh93
。ksh93
在这种情况下不会创建子 shell。
在您的具体情况下,原因完全不同:
在第一个示例中,您从输入中读取一行
在第二个示例中,您读取直到
EOF
达到
该read
命令读取输入,然后按字符分割输入IFS
,然后将单词分配给 的变量参数read
。
如果作为命令参数的单词数量多于变量read
,则最后一个变量将获得其余单词的串联。
如果单词数少于变量,则将其他变量分配为空值。
自从你点击 后EOF
,你就没有读取到任何单词,而是将一个或多个变量作为 的参数read
。这会导致所有变量分配空值。
因此发生了您意想不到的事情:EOF
导致while
循环终止,并且您echo
在循环内看不到任何命令,而在这种情况下只看到循环后的while
最终命令。echo
while
EOF
这个决赛echo
现在打印从击中清除的变量内容EOF
。