是的,外壳程序bash
尤其要小心,一次读取一行,因此它的工作方式与交互式使用时相同。
您会注意到,当文件不可搜索时(例如管道),bash
甚至一次只能读取一个字节,以确保不会读取\n
字符以外的内容。当可查找文件时,它会通过一次读取完整的块进行优化,但会在之后查找\n
。
这意味着您可以执行以下操作:
bash << \EOF
read var
var's content
echo "$var"
EOF
或编写可自我更新的脚本。如果没有保证,您将无法做到。
现在,很少有人愿意做那样的事情,而且,正如您所发现的那样,该功能往往比有用的功能妨碍更多的工作。
为了避免这种情况,您可以尝试确保不要就地修改文件(例如,修改副本,然后就地移动副本(例如sed -i
或perl -pi
,某些编辑器会这样做))。
或者您可以像这样编写脚本:
{
sleep 20
echo test
}; exit
(请注意,exit
与}
; 处于同一行很重要,尽管您也可以将其放在右括号的右方)。
要么:
main() {
sleep 20
echo test
}
main "$@"; exit
exit
在开始执行任何操作之前,shell将需要先读取脚本。这样可以确保外壳程序不会再次从脚本读取。
这意味着整个脚本将存储在内存中。
这也可能影响脚本的解析。
例如,在bash
:
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
将输出U + 00E9以UTF-8编码的格式。但是,如果将其更改为:
{
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
}
的\ue9
将在实际上是在当时该命令被解析在这种情况下是字符集进行扩展之前的export
执行命令。
还要注意,如果使用source
aka .
命令,并且在某些shell中,源文件也会遇到同样的问题。
bash
尽管不是他的source
命令在解释文件之前就完全读取了文件,但情况并非如此。如果要bash
专门编写,则可以通过在脚本开始处添加来实际使用它:
if [[ ! $already_sourced ]]; then
already_sourced=1
source "$0"; exit
fi
(尽管您可以想象将来的版本bash
会改变这种行为,但我不会依赖它,这种行为目前可以看作是一种限制(bash和AT&T ksh是唯一的POSIX式外壳,其行为可以这么说)而且这个already_sourced
技巧有点脆弱,因为它假定变量不在环境中,更不用说它会影响BASH_SOURCE变量的内容了。