我想做的是跟随。在函数内部,我需要为变量赋值,该变量的名称取自另一个变量。换句话说:
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
的变量。节省了大量的样板代码。
答案 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)
下面一次读取一行文件(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)
local
和declare
内置命令的存在可能使它反直观,即至少在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
这已被验证可以正常工作
我用它来检查各种可能性:
#!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
函数中使用的declare
和testfunc
命令没有有效地将变量应用于全局上下文(如文档所述),并且{{1} }选项尚未得到广泛支持。它还显示变量D和E在declare -g
函数内部已在全局上下文中更改(如希望的那样),而{{1 }}命令,显示testfunc
选项有效。变量F仅用于验证grep命令是否按预期工作。