Bash函数:有没有一种方法可以检查变量是否在本地定义?

6
假设您有一个带有许多选项的函数,而您决定动态存储它们的值:
#!/bin/bash
fun() {
    local OPTIND __option

    while getopts ":$(printf '%s:' {a..z} {A..Z})" __option
    do
        case $__option in
        [[:alpha:]])
            # ... 
            local "__$__option=$OPTARG"
        esac
    done

    # here you might get a conflict with external variables:
    [[ ${__a:+1} ]] && echo "option a is set"
    [[ ${__b:+1} ]] && echo "option b is set"
    # etc...
    [[ ${__Z:+1} ]] && echo "option Z is set"
}

有没有一种方法可以检查变量是否在本地定义?


1
bash 手册中:如果没有操作数,local 将本地变量列表写入标准输出。 - Renaud Pacalet
1个回答

10

如果变量使用Bash的declarelocaltypeset语句声明,那么你肯定可以检测到它是局部变量。

下面是一个示例:

#!/usr/bin/env bash

a=3
b=2

fn() {
  declare a=1
  b=7
  if local -p a >/dev/null 2>&1; then
    printf 'a is local with value %s\n' "$a"
  else
    printf 'a is not local with value %s\n' "$a"
  fi
  if local -p b >/dev/null 2>&1; then
    printf 'b is local with value %s\n' "$b"
  else
    printf 'b is not local with value %s\n' "$b"
  fi
}


fn

输出结果为:

a is local with value 1
b is not local with value 7

我把你的脚本保存在 test.sh 中,并运行了 ./test.sh,但是得到了 b is local with value 的结果。有些奇怪的事情正在发生。我认为这不是一种可靠的测试变量是否为局部变量的方法。我的 bash 版本是 5.0.17(1)-release - Philippe
@Philippe,我认为这可能是5.0.17版本中的一个错误或不同的编译设置。但在5.1.8(1)-release版本中没有问题。如果脚本告诉你b是局部变量,那么b就是局部变量。在运行函数后,在全局范围内打印b的值来验证它。如果在函数之后b=2,那么b确实是函数的局部变量。 - Léa Gris
4
我刚刚测试了版本3.2.7和4.4,它们再次表明b是本地的。只有版本5.1.4/MacOS说“b不是本地的,值为7”。因此,我认为这是5.1的一个错误(或“新功能”)。 - Philippe
2
看起来 local -p 是 Bash>5.0。不幸的是,local 也不是一个变量属性,所以在Bash<=5.0中检查的唯一方法是在 local 声明之前进行,或解析普通 local 调用的输出。 - mpe
2
看起来 local -p 是 Bash>5.0。不幸的是,local 也不是一个变量属性,所以在 Bash<=5.0 中唯一的方法是在 local 声明之前进行检查,或解析普通 local 调用的输出。 - undefined
我认为上面的方法并不适用于所有情况:似乎 local -p 只显示那些在当前函数中声明为local的变量。如果这个函数是被另一个函数调用的,并且那个函数也将相同的变量声明为local,那么在当前函数中它仍然是local的——就调用函数而言,也就是说我们看不到外部或全局版本。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接