【问题标题】:Bash Variable Scope LeakBash 变量范围泄漏
【发布时间】:2015-06-03 02:45:06
【问题描述】:

通常,我看到有关人们无法从其范围之外访问变量的问题。但是,我似乎遇到了相反的情况:我看到变量仍然具有来自内部范围的值,它们应该在之后放弃。例如(制作类似于git aliases的svn别名):

function svn() {
    case $@ in
        alias*) shift 1;
            for i in "$@"; do
                if [[ "$i" == "-t" ]];
                then
                    j="$i,$j"
                elif [[ "$i" == "-f" ]];
                    k="$i,$j"
                fi
            done

            echo "i = $i"
            echo "j = $j"
            echo "k = $k"
        ;;
    esac
}

我把它放在一个脚本中并获取它,所以它的功能被做成了 bash 的别名(我认为)。尝试使用“-t”和“-f”的各种组合运行它,你会看到变量“$i”、“$j”和“$k”在再次运行脚本时都保持它们的值,并且在脚本退出后它们在外壳中保持不变。我使用的是 Ubuntu 15.04 笔记本电脑,当我输入 Ctrl-X Ctrl-V 我的 shell 输出 GNU bash,版本 4.3.30(1)-release (x86_64-pc-linux-gnu)。

我读过的关于 bash 的所有内容都告诉我这不应该发生(诚然,我在这方面有点初学者)。脚本(或函数)退出后,变量不应保持设置,除非您在它们上使用export,而我没有。那么为什么会这样呢?

【问题讨论】:

  • 这是在您正在运行的脚本中吗?还是您正在采购然后在命令行上调用函数的文件?
  • 第二个。我认为这对于范围界定并不重要。

标签: bash shell environment-variables


【解决方案1】:

有两种不同的现象在起作用:

  1. 当变量被导出时,它们被复制到子进程的环境中。未导出的变量不会被传递。除非您明确使用 export 将它们标记为导出,否则不会导出变量。

     export LESS_OPTIONS=-R   # export so `less` sees this variable
     less
    

    不要将此与范围混淆,这是不同的。

  2. 默认情况下,内部函数变量具有全局作用域。您必须使用local 关键字来声明局部变量。否则像for i in "$@" 这样的循环将修改全局变量$i,而不是创建一个局部变量。

    svn() {
        local i j k
    
        case $@ in
            ...
        esac
    }
    

导出决定了子进程看到的内容。作用域决定函数是否修改全局变量。

【讨论】:

  • 我没有在 Internet 上的示例 bash 脚本中看到这一点。所以我会在上面的例子中使用类似local i=$i 的东西?
  • 许多野外的脚本写得不好。他们泄漏变量,他们没有正确引用变量,他们解析psls 的输出......各种废话。 Bash Guide 有一个在 for 循环之前正确使用 local i 的示例,以及注释 “函数内部的局部变量 i 与外部变量 i 的存储方式不同脚本。这允许两个循环在不干扰彼此计数器的情况下运行。"
  • 似乎 bash 的作用域类似于 JavaScript。两者都有两种作用域:全局作用域(无标识符)和函数作用域(用varlocal 声明)。我这样说对吗?我主要使用 JavaScript,所以这样的类比对我很有帮助。
  • 是的,你是对的。我从来没有建立过这种联系。我会说 JavaScript 获胜,因为您可以将 var 声明直接放在 for 循环中。在 bash 中,它必须是一个单独的命令。
  • declare 也可用于范围界定。不幸的是,不使用localdeclare 是一个常见错误。
猜你喜欢
  • 2010-09-12
  • 1970-01-01
  • 2012-10-25
  • 2012-01-31
相关资源
最近更新 更多