V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
mylovesaber
V2EX  ›  Linux

为何 shell 脚本变量传入任意方法后会被内部的循环体的同名遍历变量的值所覆盖?

  •  
  •   mylovesaber · 2023-02-23 18:57:57 +08:00 · 1201 次点击
    这是一个创建于 425 天前的主题,其中的信息可能已经有所发展或是发生改变。

    源码(后文 listA 和 listB 数组简称 A 数组和 B 数组):

    #!/bin/bash
    AA(){
        for ii in "${listB[@]}"; do   #|
            :                         #| ==> 这 AA 方法中的 for 循环目的是遍历 B 数组,但什么都不做。
        done                          #|
    }
    
    listA=(1)                  #
    listB=(a b c d)            #___这四行仅仅定义和打印出两个数组中的元素(后文结果中的前两行内容)
    echo "listA: ${listA[@]}"  #
    echo "listB: ${listB[@]}"  #
    
    for ii in "${listA[@]}"; do
        echo "在 AA 方法前的值: ${ii}" # 传 ii 给方法 AA 前看值是多少
        AA "${ii}"                  # 将遍历的 ii 传给方法 AA
        echo "在 AA 方法后的值: ${ii}" # 传 ii 给方法 AA 后看值是多少
    done
    

    输出结果:

    listA: 1
    listB: a b c d
    在 AA 方法前的值: 1
    在 AA 方法后的值: d
    

    可以看到:遍历数组 A 时所用的变量 ii 和方法内遍历数组 B 时所用变量是相同的,但这变量 ii 为何是全局变量啊?我尝试了以下写法:

    1. 只在遍历数组 A 之前加入 local ii
    2. 只在方法 AA 中遍历数组 B 之前加入 local ii
    3. 以上两个写法都安排上

    好像最终输出的都是 listB 数组的最后一个元素值,这又是怎么个操作? 有点懵,以前没遇到过,有大佬解惑吗?

    7 条回复    2023-02-23 19:37:03 +08:00
    mylovesaber
        1
    mylovesaber  
    OP
       2023-02-23 19:06:21 +08:00
    问错了。。。等重新编辑。。。
    mylovesaber
        2
    mylovesaber  
    OP
       2023-02-23 19:08:15 +08:00
    @mylovesaber 好像没问错。。。这 ii 不应该是专属于当前 for 循环的变量么?为何会成为了全局变量?
    momocraft
        3
    momocraft  
       2023-02-23 19:11:54 +08:00
    sh (bash) 的变量不是 lexical scope, 是 dynamic scope

    AA 有了 local ii 后不应该覆盖外面的 ii 能把你的完整代码贴出来看看吗
    mylovesaber
        4
    mylovesaber  
    OP
       2023-02-23 19:23:00 +08:00
    在 AA 方法中的 for 循环前后都加上 `echo $1`,可以看到打印的两次 $1 结果都是 A 数组中的元素值 1 ,说明传进去的的确是 1 ,但这是 ii 的值啊,数组内部 ii 值被循环中的 ii 替换后,为何 $1 值没变?
    mylovesaber
        5
    mylovesaber  
    OP
       2023-02-23 19:24:55 +08:00
    @momocraft 这个说法第一次听说,我一楼发的那个就是完整的测试源码,可以得到方法内部的 for 循环中 ii 值的确可以把方法外部套的循环中的 ii 值给替换掉的结论,你直接复制粘贴删掉注释运行就能看到结果
    mylovesaber
        6
    mylovesaber  
    OP
       2023-02-23 19:35:26 +08:00
    @momocraft 不好意思刚刚可能有什么操作失误的地方,local 只能用在方法内,刚刚查了下好像明白 local 生效的原因了,但有点诧异为啥别的语言 for 循环的类似 shell 的 ii 位置只能作用于该循环内,而方法内不声明 local 的话,shell for 循环中的 ii 会是全局变量
    mylovesaber
        7
    mylovesaber  
    OP
       2023-02-23 19:37:03 +08:00
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   994 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 19:55 · PVG 03:55 · LAX 12:55 · JFK 15:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.