我在Cygwin bash版本4.3.42(4)中遇到了一个奇怪的(对我而言)问题。当在函数内调用前者时,在调用脚本中声明的Shell变量不会在调用脚本中保留。
我有以下两个脚本来说明问题。 script1.sh调用script2.sh设置两个变量。如果通过script1中的函数调用script2,则变量将丢失,而如果在没有函数调用的情况下调用script2,则变量将按预期保持不变。所有对script2的调用都是通过“source”完成的。
script1.sh:
#!/usr/bin/bash
#
# calling script
#
function sourceit()
{
source scripts/script2.sh
}
sval=1
echo "$0 before sourceit(); rval=$rval sval=$sval PID=$$"
sourceit
echo "$0 after sourceit(); rval=$rval sval=$sval PID=$$"
sval=3
echo "$0 before source; rval=$rval sval=$sval PID=$$"
source scripts/script2.sh
echo "$0 after source; rval=$rval sval=$sval PID=$$"
script2.sh
#!/usr/bin/bash
#
# called script
#
echo "$0 before declare; rval=$rval sval=$sval PID=$$"
sval=2
declare -r rval=2
echo "$0 after declare; rval=$rval sval=$sval PID=$$"
结果:
scripts/script1.sh before sourceit(); rval= sval=1 PID=1752
scripts/script1.sh before declare; rval= sval=1 PID=1752
scripts/script1.sh after declare; rval=2 sval=2 PID=1752
scripts/script1.sh after sourceit(); rval= sval=2 PID=1752
scripts/script1.sh before source; rval= sval=3 PID=1752
scripts/script1.sh before declare; rval= sval=3 PID=1752
scripts/script1.sh after declare; rval=2 sval=2 PID=1752
scripts/script1.sh after source; rval=2 sval=2 PID=1752
我没有看到任何子壳被创建(到处都显示相同的PID)。
我错过了更好的bash脚本编写点吗?
答案 0 :(得分:4)
我已经开始回答这个问题,但是在推杆时我被打断了 将信息汇总起来,现在才刚刚回归。我看到John Bollinger已经完全回答了关于函数和变量范围的问题,所以我将忽略我的部分答案。
$$
我没有看到任何子壳被创建(到处都显示相同的PID)。
如果要在子shell中运行命令,它们将在子进程中运行 使用与父shell不同的PID进行处理。
然而,值得注意的是,对于Bash,子shell实际上继承了
来自父shell的$$
特殊变量的值。当我在试验子壳时,这让我有些困惑。
但是,Bash将BASHPID
特殊变量设置为shell进程的实际PID(在子shell中确实会发生变化)。以下命令序列演示了这一点。
显示当前shell的PID:
$ echo $$
1469
$ echo $BASHPID
1469
在括号内,这两个命令在子shell中运行。只有特定于Bash的BASHPID
特殊变量才会显示子shell进程的实际PID。
$ (echo $$)
1469
$ (echo $BASHPID)
8806
Compound commands上的这篇文章与您的问题相关,因为它解释了子shell 和 shell函数。
答案 1 :(得分:3)
我有以下两个脚本来说明问题。 script1.sh调用script2.sh设置两个变量。如果通过script1中的函数调用script2,则变量将丢失,
嗯不,您的输出显示变量rval
的值在从函数返回后丢失,但保留变量sval
的值。
如果在没有函数调用的情况下调用script2,则变量会按预期保持不变。所有对script2的调用都是通过“source”完成的。
由于rval
和sval
的行为存在差异,因此您应该在script2.sh
中查看处理方式的差异,etvoilà!事实证明,rval
通过内置declare
分配了其值,而sval
则直接分配了其值。查看declare
的文档,然后,我们找到:
在函数中使用时,将每个名称设置为本地名称,与
local
命令一样。
bash
中的局部变量就像大多数其他语言中的局部变量一样 - 它们与其他具有相同名称的变量不同,并且在它们的范围内,它们包含来自包含范围的类似命名的变量。因此,在每种情况下,您的代码都会在任何地方设置和检查相同的变量sval
,但它会设置并检查函数内部的不同的 rval
,而不是其他任何位置。< / p>