在函数内声明全局变量

时间:2012-03-26 11:42:39

标签: bash shell scope

我想做的是跟随。在函数内部,我需要为变量赋值,该变量的名称取自另一个变量。换句话说:

func() {  
  #  
  # Here happens something that ultimately makes $arg="var_name"
  # 
  declare -g ${arg}=5
}

func

echo ${var_name}; # Prints out "5"

上面的代码片段在bash 4.2中运行良好。但是,在4.2之前的bash中,declare没有-g选项。我在google上发现的一切都说要在函数中定义全局变量,我应该使用var=value语法,但不幸的是var本身依赖于另一个变量。 ${arg}=5也不起作用。 (它说-bash: var_name=5: command not found

对于好奇,所有这一切的原因是这个函数实际上是从脚本参数创建全局变量,即运行script --arg1=val自动创建名为arg1的值为val的变量。节省了大量的样板代码。

10 个答案:

答案 0 :(得分:14)

函数内的

declare无法按预期工作。 我需要在函数中声明的只读全局变量。 我在一个函数中尝试了这个但它不起作用:

declare -r MY_VAR=1

但是这没用。使用readonly命令执行了:

func() {
    readonly MY_VAR=1
}
func
echo $MY_VAR
MY_VAR=2

这将打印1并为第二次分配提供错误“MY_VAR:readonly variable”。

答案 1 :(得分:7)

由于标记为shell,因此请务必注意declare仅在有限的一组shell中是有效关键字,因此它是否支持-g是没有意义的。要在通用Bourne shell中执行此类操作,您只需使用eval:

eval ${arg}=5

答案 2 :(得分:6)

我认为您需要printf内置及其-v开关:

func() {
    printf -v "$var" '5'
}
var=var_name
func
echo "$var_name"

将输出5

答案 3 :(得分:3)

您可以将var = value构造为字符串,并使用bash内置命令eval对其进行评估。

答案 4 :(得分:3)

使用“eval”(或任何直接分配)可能会让您头疼特殊字符(或注入价值等问题)。

我使用“阅读”

取得了巨大的成功
$ function assign_global() {
>   local arg="$1"
>   IFS="" read -d "" $arg <<<"$2"
>}
$ assign_global MYVAR 23
echo $MYVAR
23
$ assign_global MYVAR "\"'"
"'

答案 5 :(得分:3)

如果您想要一些不那么强硬的东西,请尝试使用export代替declare -g。它现在具有环境变量的额外好处。

func() {  
#  
# Here happens something that ultimately makes $arg="var_name"
# 
export ${arg}=5
}

func

echo ${var_name}; # Prints out "5"

不幸的是,这仍然不适用于数组。

答案 6 :(得分:2)

在Bash中,为了在函数定义中声明数组变量,您可以将local命令与eval命令结合使用,如下例所示:

#!/bin/bash
function test
{
    local -g $1
    local array=( AA BB 'C C' DD)
    eval ${1}='("${array[@]}")'
}
test VAR
echo VAR=${VAR[@]:1:2}

输出将是:

$./test.sh
VAR=BB C C

适用于:GNU bash,版本4.4.18

答案 7 :(得分:0)

Eval将使用数组变量...我只需要在eval语句中单引用本地Array变量。

下面一次读取一行文件(1st arg),然后将其复制到传递给get_file第二个arg的变量名。

get_file () {
  declare -a Array=();
  while read line; do
    Array=("${Array[@]}" "($line)")
  done < ${1}
  eval ${2}='("${Array[@]}")'
  unset Array
}

declare -a my_array=();
get_file /etc/myfile.conf my_array
echo ${#my_array[@]}

答案 8 :(得分:0)

也许您可以使用以下函数在bash(&lt; 4.2)中动态分配全局变量。如果&gt;传递2个args,然后该值将是数组类型。 E.G

_set2globals variable_name arg1 [arg2] [arg3] [...]

来源:

# dynamically set $variable_name($1)=$values($2...) to globals scope
function _set2globals()
{
    if (( $# < 2 )); then
        printf "$FUNCNAME: expect at least 2 argument, but %d you given.\n" $# >&2
        exit 1
    fi
    local ___pattern_='^[_a-zA-Z][_0-9a-zA-Z]*$'
    if [[ ! $1 =~ $___pattern_ ]]; then
        printf "$FUNCNAME: invalid variable name: %s.\n" "$1" >&2
        exit 1
    fi
    local __variable__name__=$1
    shift
    local ___v_
    local ___values_=()
    while (($# > 0)); do
        ___v_=\'${1//"'"/"'\''"}\'
        ___values_=("${___values_[@]}" "$___v_") # push to array
        shift
    done

    eval $__variable__name__=\("${___values_[@]}"\)
}

答案 9 :(得分:0)

localdeclare内置命令的存在可能使它反直观,即至少在Bash上实际上可以从内置的export获得所需的功能。

根据Bash手册,export命令具有-n选项,该选项“ 导致导出属性从每个名称中删除”。在声明变量的值就在前面时也是如此。

以下代码段演示了用法:

VAR=old-value
function func () {
    export -n "$1=$2"
}
func VAR new-value
echo "VAR=$VAR"     # prints VAR=new-value

一个人可以创建自己的global函数,并将其在其他函数中使用:

VAR=old-value
function global () {
    export -n "$1=$2"
}
function main () {
    global VAR "$1"
}
main main-value
echo "VAR=$VAR"            # prints VAR=main-value

这已被验证可以正常工作

  • 在(现代)OS / 390 z / OS上运行的旧Bash 2.03.0(1)
  • 在macOS 10.15上的Bash 3.2.57(1)上
  • 在CentOS 6上的Bash 4.1.2(2)上

我用它来检查各种可能性:

#!env bash

export LANG=C LC_ALL=C

A=a0
B=b0
C=c0
D=d0
E=e0
export F=f0

function testfunc () {
    local "$1=$2"       ; shift 2
    declare "$1=$2"     ; shift 2
    declare -g "$1=$2"  ; shift 2
    export -n "$1=$2"   ; shift 2
    export "$1=$2"
}

echo "$A/$B/$C/$D/$E"
testfunc A a1 B b1 C c1 D d1 E e1
echo "$A/$B/$C/$D/$E"

export -p | grep -E '^declare -x [ABCDEF]='

对于macOS 10.15,显示的输出与此类似:

$ bash test.sh
a0/b0/c0/d0/e0
test.sh: line 15: declare: -g: invalid option
declare: usage: declare [-afFirtx] [-p] [name[=value] ...]
a0/b0/c0/d1/e1
declare -x E="e1"
declare -x F="f0"

输出显示local函数中使用的declaretestfunc命令没有有效地将变量应用于全局上下文(如文档所述),并且{{1} }选项尚未得到广泛支持。它还显示变量D和E在declare -g函数内部已在全局上下文中更改(如希望的那样),而{{1 }}命令,显示testfunc选项有效。变量F仅用于验证grep命令是否按预期工作。