Tom*_*s F 438 string bash function return-value
我想从Bash函数返回一个字符串.
我将在java中编写示例以显示我想要做的事情:
public String getSomeString() {
return "tadaa";
}
String variable = getSomeString();
Run Code Online (Sandbox Code Playgroud)
以下示例适用于bash,但有更好的方法吗?
function getSomeString {
echo "tadaa"
}
VARIABLE=$(getSomeString)
Run Code Online (Sandbox Code Playgroud)
Phi*_*ipp 272
我知道没有更好的方法.Bash只知道写入stdout的状态代码(整数)和字符串.
bst*_*rre 191
您可以让函数将变量作为第一个arg,并使用要返回的字符串修改变量.
#!/bin/bash
set -x
function pass_back_a_string() {
eval "$1='foo bar rab oof'"
}
return_var=''
pass_back_a_string return_var
echo $return_var
Run Code Online (Sandbox Code Playgroud)
打印"foo bar rab oof".
编辑:在适当的地方添加引用,以允许字符串中的空格来解决@Luca Borrione的评论.
编辑:作为演示,请参阅以下程序.这是一个通用解决方案:它甚至允许您将字符串接收到局部变量中.
#!/bin/bash
set -x
function pass_back_a_string() {
eval "$1='foo bar rab oof'"
}
return_var=''
pass_back_a_string return_var
echo $return_var
function call_a_string_func() {
local lvar=''
pass_back_a_string lvar
echo "lvar='$lvar' locally"
}
call_a_string_func
echo "lvar='$lvar' globally"
Run Code Online (Sandbox Code Playgroud)
这打印:
+ return_var=
+ pass_back_a_string return_var
+ eval 'return_var='\''foo bar rab oof'\'''
++ return_var='foo bar rab oof'
+ echo foo bar rab oof
foo bar rab oof
+ call_a_string_func
+ local lvar=
+ pass_back_a_string lvar
+ eval 'lvar='\''foo bar rab oof'\'''
++ lvar='foo bar rab oof'
+ echo 'lvar='\''foo bar rab oof'\'' locally'
lvar='foo bar rab oof' locally
+ echo 'lvar='\'''\'' globally'
lvar='' globally
Run Code Online (Sandbox Code Playgroud)
编辑:这表明原始变量的值是在功能可用,进行了错误@Xichen李在评论批评.
#!/bin/bash
set -x
function pass_back_a_string() {
eval "echo in pass_back_a_string, original $1 is \$$1"
eval "$1='foo bar rab oof'"
}
return_var='original return_var'
pass_back_a_string return_var
echo $return_var
function call_a_string_func() {
local lvar='original lvar'
pass_back_a_string lvar
echo "lvar='$lvar' locally"
}
call_a_string_func
echo "lvar='$lvar' globally"
Run Code Online (Sandbox Code Playgroud)
这给出了输出:
+ return_var='original return_var'
+ pass_back_a_string return_var
+ eval 'echo in pass_back_a_string, original return_var is $return_var'
++ echo in pass_back_a_string, original return_var is original return_var
in pass_back_a_string, original return_var is original return_var
+ eval 'return_var='\''foo bar rab oof'\'''
++ return_var='foo bar rab oof'
+ echo foo bar rab oof
foo bar rab oof
+ call_a_string_func
+ local 'lvar=original lvar'
+ pass_back_a_string lvar
+ eval 'echo in pass_back_a_string, original lvar is $lvar'
++ echo in pass_back_a_string, original lvar is original lvar
in pass_back_a_string, original lvar is original lvar
+ eval 'lvar='\''foo bar rab oof'\'''
++ lvar='foo bar rab oof'
+ echo 'lvar='\''foo bar rab oof'\'' locally'
lvar='foo bar rab oof' locally
+ echo 'lvar='\'''\'' globally'
lvar='' globally
Run Code Online (Sandbox Code Playgroud)
小智 96
上面的所有答案都忽略了bash手册页中所述的内容.
示例代码
#!/bin/bash
f()
{
echo function starts
local WillNotExists="It still does!"
DoesNotExists="It still does!"
echo function ends
}
echo $DoesNotExists #Should print empty line
echo $WillNotExists #Should print empty line
f #Call the function
echo $DoesNotExists #Should print It still does!
echo $WillNotExists #Should print empty line
Run Code Online (Sandbox Code Playgroud)
并输出
$ sh -x ./x.sh
+ echo
+ echo
+ f
+ echo function starts
function starts
+ local 'WillNotExists=It still does!'
+ DoesNotExists='It still does!'
+ echo function ends
function ends
+ echo It still 'does!'
It still does!
+ echo
Run Code Online (Sandbox Code Playgroud)
同样在pdksh和ksh下这个脚本也是一样的!
zen*_*aan 44
Bash,自版本4.3,2014年2月(?),明确支持引用变量或名称引用(namerefs),超出"eval",具有相同的有益性能和间接效果,并且在脚本中可能更清晰,也更难"忘记'eval'并且必须修复此错误":
declare [-aAfFgilnrtux] [-p] [name[=value] ...]
typeset [-aAfFgilnrtux] [-p] [name[=value] ...]
Declare variables and/or give them attributes
...
-n Give each name the nameref attribute, making it a name reference
to another variable. That other variable is defined by the value
of name. All references and assignments to name, except for?
changing the -n attribute itself, are performed on the variable
referenced by name's value. The -n attribute cannot be applied to
array variables.
...
When used in a function, declare and typeset make each name local,
as with the local command, unless the -g option is supplied...
Run Code Online (Sandbox Code Playgroud)
并且:
参数
可以使用声明或本地内置命令的-n选项为变量分配nameref属性(请参阅下面的declare和local的描述)以创建nameref或对另一个变量的引用.这允许间接操纵变量.每当引用或赋值给nameref变量时,操作实际上是对nameref变量的值指定的变量执行的.在shell函数中通常使用nameref来引用其名称作为参数传递给函数的变量.例如,如果变量名称作为第一个参数传递给shell函数,则运行
Run Code Online (Sandbox Code Playgroud)declare -n ref=$1
函数内部创建一个nameref变量ref,其值是作为第一个参数传递的变量名.ref的引用和赋值被视为对名称传递为$ $ 1的变量的引用和赋值.如果for循环中的控制变量具有nameref属性,则单词列表可以是shell变量列表,并且当执行循环时,将依次为列表中的每个单词建立名称引用.数组变量不能给出-n属性.但是,nameref变量可以引用数组变量和下标数组变量.可以使用unset内置的-n选项取消设置Namerefs.否则,如果使用nameref变量的名称作为参数执行unset,则将取消设置由nameref变量引用的变量.
例如(编辑2 :(谢谢Ron)命名空间(前缀)函数内部变量名称,以最小化外部变量冲突,最终应该正确回答,Karsten在评论中提出的问题):
# $1 : string; your variable to contain the return value
function return_a_string () {
declare -n ret=$1
local MYLIB_return_a_string_message="The date is "
MYLIB_return_a_string_message+=$(date)
ret=$MYLIB_return_a_string_message
}
Run Code Online (Sandbox Code Playgroud)
并测试此示例:
$ return_a_string result; echo $result
The date is 20160817
Run Code Online (Sandbox Code Playgroud)
请注意,bash"declare"builtin在函数中使用时,默认使声明变量为"local"," - n"也可以与"local"一起使用.
我更喜欢将"重要声明"变量与"无聊的本地"变量区分开来,因此以这种方式使用"declare"和"local"作为文档.
编辑1 - (回应Karsten的评论) - 我不能再在下面添加评论,但Karsten的评论让我思考,所以我做了以下测试,哪些工作精细,AFAICT - Karsten如果你读到这个,请提供一套精确的来自命令行的测试步骤,显示您认为存在的问题,因为以下步骤可以正常工作:
$ return_a_string ret; echo $ret
The date is 20170104
Run Code Online (Sandbox Code Playgroud)
(在将上述函数粘贴到bash术语之后,我刚刚运行了这个 - 正如您所看到的,结果运行得很好.)
Mar*_*451 34
像上面的bstpierre一样,我使用并建议使用显式命名输出变量:
function some_func() # OUTVAR ARG1
{
local _outvar=$1
local _result # Use some naming convention to avoid OUTVARs to clash
... some processing ....
eval $_outvar=\$_result # Instead of just =$_result
}
Run Code Online (Sandbox Code Playgroud)
注意使用引用$.这将避免以$result
shell特殊字符解释内容.我发现这比捕获回声的成语快一个数量级result=$(some_func "arg1")
.使用MSYS上的bash速度差异显得更加显着,其中从函数调用捕获的stdout几乎是灾难性的.
发送局部变量是可以的,因为本地变量在bash中是动态范围的:
function another_func() # ARG
{
local result
some_func result "$1"
echo result is $result
}
Run Code Online (Sandbox Code Playgroud)
chi*_*org 22
您还可以捕获函数输出:
#!/bin/bash
function getSomeString() {
echo "tadaa!"
}
return_var=$(getSomeString)
echo $return_var
# Alternative syntax:
return_var=`getSomeString`
echo $return_var
Run Code Online (Sandbox Code Playgroud)
看起来很奇怪,但比使用全局变量恕我直言更好.传递参数像往常一样工作,只需将它们放在大括号或反引号中.
小智 12
如前所述,从函数返回字符串的"正确"方法是使用命令替换.如果函数还需要输出到控制台(如上面提到的@Mani),请在函数的开头创建一个临时fd并重定向到控制台.在返回字符串之前关闭临时fd.
#!/bin/bash
# file: func_return_test.sh
returnString() {
exec 3>&1 >/dev/tty
local s=$1
s=${s:="some default string"}
echo "writing directly to console"
exec 3>&-
echo "$s"
}
my_string=$(returnString "$*")
echo "my_string: [$my_string]"
Run Code Online (Sandbox Code Playgroud)
执行没有参数的脚本会产生......
# ./func_return_test.sh
writing directly to console
my_string: [some default string]
Run Code Online (Sandbox Code Playgroud)
希望这有助于人们
-Andy
Tom*_*Żuk 10
其他人写道:最直接,最强大的解决方案是使用命令替换.
assign()
{
local x
x="Test"
echo "$x"
}
x=$(assign) # This assigns string "Test" to x
Run Code Online (Sandbox Code Playgroud)
缺点是性能,因为这需要一个单独的过程.
本主题中提出的另一种技术,即传递一个变量的名称作为参数赋值,有副作用,我不推荐它的基本形式.问题是您可能需要函数中的一些变量来计算返回值,并且可能会发生用于存储返回值的变量的名称将干扰其中一个:
assign()
{
local x
x="Test"
eval "$1=\$x"
}
assign y # This assigns string "Test" to y, as expected
assign x # This will NOT assign anything to x in this scope
# because the name "x" is declared as local inside the function
Run Code Online (Sandbox Code Playgroud)
当然,您可能不会将函数的内部变量声明为本地变量,但实际上您应该始终这样做,否则,如果存在具有相同名称的变量,您可能会意外地覆盖父作用域中的不相关变量. .
一种可能的解决方法是将传递的变量显式声明为全局变量:
assign()
{
local x
eval declare -g $1
x="Test"
eval "$1=\$x"
}
Run Code Online (Sandbox Code Playgroud)
如果名称"x"作为参数传递,则函数体的第二行将覆盖先前的本地声明.但是名称本身可能仍会干扰,因此如果您打算在将返回值写入之前使用先前存储在传递变量中的值,请注意必须在最开始时将其复制到另一个局部变量中; 否则结果将无法预测!此外,这只适用于最新版本的BASH,即4.2.更多可移植代码可能会使用具有相同效果的显式条件结构:
assign()
{
if [[ $1 != x ]]; then
local x
fi
x="Test"
eval "$1=\$x"
}
Run Code Online (Sandbox Code Playgroud)
也许最优雅的解决方案是为函数返回值保留一个全局名称,并在您编写的每个函数中始终如一地使用它.
您可以使用全局变量:
declare globalvar='some string'
string ()
{
eval "$1='some other string'"
} # ---------- end of function string ----------
string globalvar
echo "'${globalvar}'"
Run Code Online (Sandbox Code Playgroud)
这给了
'some other string'
Run Code Online (Sandbox Code Playgroud)
为了说明我对Andy的答案的评论,使用额外的文件描述符操作来避免使用/dev/tty
:
#!/bin/bash
exec 3>&1
returnString() {
exec 4>&1 >&3
local s=$1
s=${s:="some default string"}
echo "writing to stdout"
echo "writing to stderr" >&2
exec >&4-
echo "$s"
}
my_string=$(returnString "$*")
echo "my_string: [$my_string]"
Run Code Online (Sandbox Code Playgroud)
但仍然很讨厌.
归档时间: |
|
查看次数: |
306318 次 |
最近记录: |