如何从 bash 脚本中的函数内部连接到字符串变量?
How to concatenate to string variable from inside function in bash script?
我希望能够调用一个函数,并保留该函数将对字符串执行的所有修改。
例如:
我试过这个脚本
#!/bin/bash
change_string() {
var=
var+=",Hello2"
echo "Function: $var"
}
myString="Hello1"
change_string $myString
echo "Main: $myString"
这将打印出:
Function: Hello1,Hello2
Main: Hello1
有没有什么方法可以更改函数调用中的 $myString,但将这些更改保留在 main 中?我想我可能错过了 bash 中与传递引用相关的内容?
Bash
是少数具有动态范围的语言之一(与通常的词法范围不同)。这意味着函数正在访问它们定义的最后一个范围内的变量(可能是赋值或带有 declare
或 local
的声明)。
例如:
#!/bin/bash
fun() {
x="newval"
}
x=start
echo "$x"
fun
echo "$x"
将打印:
start
newval
这个简单的例子看起来 x
是一个简单的全局变量,但它不止于此(作用域是动态嵌套的,总是访问 last/previous 作用域)。
因此,如果您想更改函数中的变量,只需更改即可。
#!/bin/bash
change_string() {
myString+=",Hello2"
}
myString="Hello1"
change_string $myString
echo "Main: $myString"
你甚至可以更改变量"by reference",如果你传递变量的名称,然后使用declare -g
设置(在外部范围内)通过将文本附加到当前值(通过间接扩展访问),我们知道其名称 (varname
) 的变量的值:
change_string() {
varname=""
declare -g "$varname"="${!varname},Hello2"
}
myString="Hello1"
change_string myString
# myString is now "Hello1,Hello2"
使用 Bash 4.3+(namerefs!)
bash 的现代版本提供 "nameref" 支持,允许一个变量引用另一个。
#!/usr/bin/env bash
case $BASH_VERSION in
[123].*|4.[012].*) echo "This needs bash 4.3 or newer" >&2; exit 1;;
esac
# local variable is prefixed because this will fail if we're passed a variable name we use
# internally; prefixing the local names makes such collisions unlikely.
change_string() {
# make change_string__var an alias for the variable named in our argument
declare -n change_string__var=
# append to that variable
change_string__var+=",Hello2"
# ...and log the new value, 'cuz that's what the original code did.
echo "Function: $change_string__var"
}
myString="Hello1"
change_string myString ## pass variable **name**, not variable value
echo "Main: $myString"
With Bash 3.x+(间接求值+间接赋值)
或者,作为一种不太新颖的方法,可以使用 ${!var}
进行间接引用,并使用 printf -v
进行间接赋值。
#!/usr/bin/env bash
change_string() {
# Store the variable name in a regular local variable
local change_string__var=
# Use ${!var} to get the value of the variable thus named
local change_string__val=${!change_string__var}
# Use ''printf -v varname ...'' to assign a new value
printf -v "$change_string__var" %s "${change_string__val},Hello2"
}
myString="Hello1"
change_string myString
echo "Main: $myString"
您必须将变量的 名称 传递给您的函数,而不是它的值。一旦你这样做了,有几个选项。
最简单的可能是使用 nameref(需要 bash
4.3 或更高版本):
change_string() {
declare -n var=
var+=",Hello2"
}
$ foo="Hello1"
$ change_string foo
$ echo "$foo"
Hello1,Hello2
在引入 namerefs 之前,您可以使用 declare -g
,这需要 bash
4.2 或更高版本:
change_string () {
var=
old_val=${!var}
declare -g "=${old_val},Hello2"
}
在 4.2 之前,您几乎一直在使用 eval
并且祈祷您没有被代码注入攻击咬伤。
change_string () {
var=
eval "=$,Hello2"
}
不过,None 中的方法完全是万无一失的;请参阅 Bash FAQ 048 的 this section。我的建议是尽量避免需要这样的功能。
我希望能够调用一个函数,并保留该函数将对字符串执行的所有修改。
例如: 我试过这个脚本
#!/bin/bash
change_string() {
var=
var+=",Hello2"
echo "Function: $var"
}
myString="Hello1"
change_string $myString
echo "Main: $myString"
这将打印出:
Function: Hello1,Hello2
Main: Hello1
有没有什么方法可以更改函数调用中的 $myString,但将这些更改保留在 main 中?我想我可能错过了 bash 中与传递引用相关的内容?
Bash
是少数具有动态范围的语言之一(与通常的词法范围不同)。这意味着函数正在访问它们定义的最后一个范围内的变量(可能是赋值或带有 declare
或 local
的声明)。
例如:
#!/bin/bash
fun() {
x="newval"
}
x=start
echo "$x"
fun
echo "$x"
将打印:
start
newval
这个简单的例子看起来 x
是一个简单的全局变量,但它不止于此(作用域是动态嵌套的,总是访问 last/previous 作用域)。
因此,如果您想更改函数中的变量,只需更改即可。
#!/bin/bash
change_string() {
myString+=",Hello2"
}
myString="Hello1"
change_string $myString
echo "Main: $myString"
你甚至可以更改变量"by reference",如果你传递变量的名称,然后使用declare -g
设置(在外部范围内)通过将文本附加到当前值(通过间接扩展访问),我们知道其名称 (varname
) 的变量的值:
change_string() {
varname=""
declare -g "$varname"="${!varname},Hello2"
}
myString="Hello1"
change_string myString
# myString is now "Hello1,Hello2"
使用 Bash 4.3+(namerefs!)
bash 的现代版本提供 "nameref" 支持,允许一个变量引用另一个。
#!/usr/bin/env bash
case $BASH_VERSION in
[123].*|4.[012].*) echo "This needs bash 4.3 or newer" >&2; exit 1;;
esac
# local variable is prefixed because this will fail if we're passed a variable name we use
# internally; prefixing the local names makes such collisions unlikely.
change_string() {
# make change_string__var an alias for the variable named in our argument
declare -n change_string__var=
# append to that variable
change_string__var+=",Hello2"
# ...and log the new value, 'cuz that's what the original code did.
echo "Function: $change_string__var"
}
myString="Hello1"
change_string myString ## pass variable **name**, not variable value
echo "Main: $myString"
With Bash 3.x+(间接求值+间接赋值)
或者,作为一种不太新颖的方法,可以使用 ${!var}
进行间接引用,并使用 printf -v
进行间接赋值。
#!/usr/bin/env bash
change_string() {
# Store the variable name in a regular local variable
local change_string__var=
# Use ${!var} to get the value of the variable thus named
local change_string__val=${!change_string__var}
# Use ''printf -v varname ...'' to assign a new value
printf -v "$change_string__var" %s "${change_string__val},Hello2"
}
myString="Hello1"
change_string myString
echo "Main: $myString"
您必须将变量的 名称 传递给您的函数,而不是它的值。一旦你这样做了,有几个选项。
最简单的可能是使用 nameref(需要 bash
4.3 或更高版本):
change_string() {
declare -n var=
var+=",Hello2"
}
$ foo="Hello1"
$ change_string foo
$ echo "$foo"
Hello1,Hello2
在引入 namerefs 之前,您可以使用 declare -g
,这需要 bash
4.2 或更高版本:
change_string () {
var=
old_val=${!var}
declare -g "=${old_val},Hello2"
}
在 4.2 之前,您几乎一直在使用 eval
并且祈祷您没有被代码注入攻击咬伤。
change_string () {
var=
eval "=$,Hello2"
}
不过,None 中的方法完全是万无一失的;请参阅 Bash FAQ 048 的 this section。我的建议是尽量避免需要这样的功能。