Bash可变范围泄漏

try*_*sis 4 bash shell environment-variables

通常,我会看到有关人们无法从其范围之外访问变量的问题.然而,我似乎正在经历相反的情况:我看到变量仍然具有内部范围的值,他们应该在之后放弃.例如(使svn别名类似于git别名):

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
}
Run Code Online (Sandbox Code Playgroud)

我把它放在一个脚本中并将其源化,因此它的功能被制作为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它们,我没有.那为什么会这样呢?

Joh*_*ica 6

有两种不同的现象:

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

     export LESS_OPTIONS=-R   # export so `less` sees this variable
     less
    
    Run Code Online (Sandbox Code Playgroud)

    不要将它与范围混淆,这是不同的.

  2. 内部函数变量默认具有全局范围.您必须使用local关键字来声明局部变量.否则,类似的循环for i in "$@"将修改全局变量$i而不是创建局部变量.

    svn() {
        local i j k
    
        case $@ in
            ...
        esac
    }
    
    Run Code Online (Sandbox Code Playgroud)

导出确定子进程看到的内容.范围确定函数是否修改全局变量.

  • 野外的许多剧本编写得很糟糕.他们泄漏变量,他们没有正确引用变量,他们解析`ps`和`ls`的输出...各种废话.[Bash指南](http://mywiki.wooledge.org/BashGuide/CompoundCommands#Functions)有一个在`for`循环之前正确使用`local i`的例子,以及note,*"局部变量`函数内部的i`与外部脚本中的变量`i`的存储方式不同.这允许两个循环操作而不会干扰彼此的计数器."* (2认同)