我想从Bash函数返回一个字符串。
我将用java写这个例子来说明我想做什么:
public String getSomeString() {
return "tadaa";
}
String variable = getSomeString();
下面的示例可以在bash中工作,但是是否有更好的方法来做到这一点?
function getSomeString {
echo "tadaa"
}
VARIABLE=$(getSomeString)
我想从Bash函数返回一个字符串。
我将用java写这个例子来说明我想做什么:
public String getSomeString() {
return "tadaa";
}
String variable = getSomeString();
下面的示例可以在bash中工作,但是是否有更好的方法来做到这一点?
function getSomeString {
echo "tadaa"
}
VARIABLE=$(getSomeString)
当前回答
如前所述,从函数返回字符串的“正确”方法是使用命令替换。如果函数也需要输出到控制台(如@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]"
执行没有参数的脚本会产生…
# ./func_return_test.sh
writing directly to console
my_string: [some default string]
希望这能帮助到人们
安迪
其他回答
agt@agtsoft:~/temp$ cat ./fc
#!/bin/sh
fcall='function fcall { local res p=$1; shift; fname $*; eval "$p=$res"; }; fcall'
function f1 {
res=$[($1+$2)*2];
}
function f2 {
local a;
eval ${fcall//fname/f1} a 2 3;
echo f2:$a;
}
a=3;
f2;
echo after:a=$a, res=$res
agt@agtsoft:~/temp$ ./fc
f2:10
after:a=3, res=
提醒薇姬·罗嫩,考虑一下下面的代码
function use_global
{
eval "$1='changed using a global var'"
}
function capture_output
{
echo "always changed"
}
function test_inside_a_func
{
local _myvar='local starting value'
echo "3. $_myvar"
use_global '_myvar'
echo "4. $_myvar"
_myvar=$( capture_output )
echo "5. $_myvar"
}
function only_difference
{
local _myvar='local starting value'
echo "7. $_myvar"
local use_global '_myvar'
echo "8. $_myvar"
local _myvar=$( capture_output )
echo "9. $_myvar"
}
declare myvar='global starting value'
echo "0. $myvar"
use_global 'myvar'
echo "1. $myvar"
myvar=$( capture_output )
echo "2. $myvar"
test_inside_a_func
echo "6. $_myvar" # this was local inside the above function
only_difference
将会给
0. global starting value
1. changed using a global var
2. always changed
3. local starting value
4. changed using a global var
5. always changed
6.
7. local starting value
8. local starting value
9. always changed
也许正常的场景是使用test_inside_a_func函数中使用的语法,因此在大多数情况下可以同时使用这两种方法,尽管捕获输出是在任何情况下都能工作的更安全的方法,它模仿在其他语言中可以找到的函数的返回值,Vicky Ronnen正确地指出了这一点。
虽然有很多很好的答案,但它们都不是我想要的方式。下面是我的解决方案,要点如下:
帮助健忘的程序员
至少我会努力记住错误检查之后,像这样:
允许用换行字符\n赋值
有些解决方案不允许这样做,因为有些解决方案忘记了要赋值周围的单引号。正确的方法:eval "${returnVariable}='${value}'"或者更好:参见下面的下一点。
使用printf代替eval
只需尝试使用类似myFunction "date && var2"的东西来解决这里的一些假定的解决方案。Eval会执行给它的任何东西。我只想分配值,所以我使用printf -v "${returnVariable}" "%s" "${value}"代替。
对变量名冲突的封装和保护
如果一个不同的用户或至少是对函数了解较少的人(这可能是几个月后的我)正在使用myFunction,我不希望他们知道他必须使用全局返回值名称或禁止使用某些变量名称。这就是为什么我在myFunction的顶部添加了一个名称检查:
if [[ "${1}" = "returnVariable" ]]; then
echo "Cannot give the ouput to \"returnVariable\" as a variable with the same name is used in myFunction()!"
echo "If that is still what you want to do please do that outside of myFunction()!"
return 1
fi
注意,如果你需要检查很多变量,这也可以放在函数本身中。 如果我仍然想使用相同的名称(这里:returnVariable),我只是创建了一个缓冲变量,给myFunction,然后复制值returnVariable。
就是这样:
myFunction ():
myFunction() {
if [[ "${1}" = "returnVariable" ]]; then
echo "Cannot give the ouput to \"returnVariable\" as a variable with the same name is used in myFunction()!"
echo "If that is still what you want to do please do that outside of myFunction()!"
return 1
fi
if [[ "${1}" = "value" ]]; then
echo "Cannot give the ouput to \"value\" as a variable with the same name is used in myFunction()!"
echo "If that is still what you want to do please do that outside of myFunction()!"
return 1
fi
local returnVariable="${1}"
local value=$'===========\nHello World\n==========='
echo "setting the returnVariable now..."
printf -v "${returnVariable}" "%s" "${value}"
}
测试用例:
var1="I'm not greeting!"
myFunction var1
[[ $? -eq 0 ]] && echo "myFunction(): SUCCESS" || echo "myFunction(): FAILURE"
printf "var1:\n%s\n" "${var1}"
# Output:
# setting the returnVariable now...
# myFunction(): SUCCESS
# var1:
# ===========
# Hello World
# ===========
returnVariable="I'm not greeting!"
myFunction returnVariable
[[ $? -eq 0 ]] && echo "myFunction(): SUCCESS" || echo "myFunction(): FAILURE"
printf "returnVariable:\n%s\n" "${returnVariable}"
# Output
# Cannot give the ouput to "returnVariable" as a variable with the same name is used in myFunction()!
# If that is still what you want to do please do that outside of myFunction()!
# myFunction(): FAILURE
# returnVariable:
# I'm not greeting!
var2="I'm not greeting!"
myFunction "date && var2"
[[ $? -eq 0 ]] && echo "myFunction(): SUCCESS" || echo "myFunction(): FAILURE"
printf "var2:\n%s\n" "${var2}"
# Output
# setting the returnVariable now...
# ...myFunction: line ..: printf: `date && var2': not a valid identifier
# myFunction(): FAILURE
# var2:
# I'm not greeting!
myFunction var3
[[ $? -eq 0 ]] && echo "myFunction(): SUCCESS" || echo "myFunction(): FAILURE"
printf "var3:\n%s\n" "${var3}"
# Output
# setting the returnVariable now...
# myFunction(): SUCCESS
# var3:
# ===========
# Hello World
# ===========
在我的程序中,按照约定,这就是预先存在的$REPLY变量的用途,read正是为此目的而使用它。
function getSomeString {
REPLY="tadaa"
}
getSomeString
echo $REPLY
这种回声
tadaa
但是为了避免冲突,任何其他全局变量都可以。
declare result
function getSomeString {
result="tadaa"
}
getSomeString
echo $result
如果这还不够,我推荐Markarian451的解决方案。
像上面的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
}
注意引用$的用法。这将避免将$result中的内容解释为shell特殊字符。我发现这比result=$(some_func "arg1")捕获回声的习惯用法快一个数量级。在MSYS上使用bash时,速度差异似乎更加显著,从函数调用中捕获标准输出几乎是灾难性的。
可以发送一个局部变量,因为局部变量在bash中是动态作用域的:
function another_func() # ARG
{
local result
some_func result "$1"
echo result is $result
}