当脚本来自函数内时,Bash shell变量会丢失

时间:2015-12-22 20:29:33

标签: bash function shell scope

我在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脚本编写点吗?

2 个答案:

答案 0 :(得分:4)

我已经开始回答这个问题,但是在推杆时我被打断了 将信息汇总起来,现在才刚刚回归。我看到John Bollinger已经完全回答了关于函数和变量范围的问题,所以我将忽略我的部分答案。

子shell和$$

  

我没有看到任何子壳被创建(到处都显示相同的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

相关链接

答案 1 :(得分:3)

  

我有以下两个脚本来说明问题。 script1.sh调用script2.sh设置两个变量。如果通过script1中的函数调用script2,则变量将丢失,

嗯不,您的输出显示变量rval的值在从函数返回后丢失,但保留变量sval的值。

  

如果在没有函数调用的情况下调用script2,则变量会按预期保持不变。所有对script2的调用都是通过“source”完成的。

由于rvalsval的行为存在差异,因此您应该在script2.sh中查看处理方式的差异,etvoilà!事实证明,rval通过内置declare分配了其值,而sval则直接分配了其值。查看declare的文档,然后,我们找到:

  

在函数中使用时,将每个名称设置为本地名称,与local命令一样。

bash中的局部变量就像大多数其他语言中的局部变量一样 - 它们与其他具有相同名称的变量不同,并且在它们的范围内,它们包含来自包含范围的类似命名的变量。因此,在每种情况下,您的代码都会在任何地方设置和检查相同的变量sval,但它会设置并检查函数内部的不同的 rval,而不是其他任何位置。< / p>