我想从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)
当前回答
我想,所有的选择都已经列举出来了。选择一种可以归结为最适合您的特定应用程序的样式,因此,我想提供一种我认为有用的特定样式。在bash中,变量和函数不在同一个命名空间中。因此,将同名变量视为函数值是一种约定,如果严格应用它,我发现这种约定可以最大限度地减少名称冲突并增强可读性。一个来自现实生活的例子:
UnGetChar=
function GetChar() {
# assume failure
GetChar=
# if someone previously "ungot" a char
if ! [ -z "$UnGetChar" ]; then
GetChar="$UnGetChar"
UnGetChar=
return 0 # success
# else, if not at EOF
elif IFS= read -N1 GetChar ; then
return 0 # success
else
return 1 # EOF
fi
}
function UnGetChar(){
UnGetChar="$1"
}
下面是一个使用这些函数的例子:
function GetToken() {
# assume failure
GetToken=
# if at end of file
if ! GetChar; then
return 1 # EOF
# if start of comment
elif [[ "$GetChar" == "#" ]]; then
while [[ "$GetChar" != $'\n' ]]; do
GetToken+="$GetChar"
GetChar
done
UnGetChar "$GetChar"
# if start of quoted string
elif [ "$GetChar" == '"' ]; then
# ... et cetera
如您所见,返回状态是供您在需要时使用的,如果不需要则忽略它。“返回”变量同样可以被使用或忽略,但当然只有在函数被调用之后。
当然,这只是一种惯例。您可以在返回之前不设置相关值(因此我的约定总是在函数开始时将其为空),或者通过再次调用函数(可能是间接地)来破坏它的值。不过,如果我发现自己大量使用bash函数,我觉得这种约定非常有用。
相反的情绪,这是一个迹象,一个应该。“转到perl”,我的哲学是,对于管理任何语言的复杂性,约定总是很重要的。
其他回答
在我的程序中,按照约定,这就是预先存在的$REPLY变量的用途,read正是为此目的而使用它。
function getSomeString {
REPLY="tadaa"
}
getSomeString
echo $REPLY
这种回声
tadaa
但是为了避免冲突,任何其他全局变量都可以。
declare result
function getSomeString {
result="tadaa"
}
getSomeString
echo $result
如果这还不够,我推荐Markarian451的解决方案。
为了说明我对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]"
不过还是很恶心。
提醒薇姬·罗嫩,考虑一下下面的代码
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正确地指出了这一点。
你可以让这个函数把一个变量作为第一个参数,然后用你想要返回的字符串修改变量。
#!/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
打印“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"
这个打印:
+ 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
编辑:演示原始变量的值在函数中可用,正如@Xichen Li在评论中错误地批评的那样。
#!/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"
输出如下:
+ 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
Bash模式返回标量和数组值对象:
定义
url_parse() { # parse 'url' into: 'url_host', 'url_port', ...
local "$@" # inject caller 'url' argument in local scope
local url_host="..." url_path="..." # calculate 'url_*' components
declare -p ${!url_*} # return only 'url_*' object fields to the caller
}
调用
main() { # invoke url parser and inject 'url_*' results in local scope
eval "$(url_parse url=http://host/path)" # parse 'url'
echo "host=$url_host path=$url_path" # use 'url_*' components
}