我想从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”,我的哲学是,对于管理任何语言的复杂性,约定总是很重要的。

其他回答

您可以回显字符串,但通过将函数(|)连接到其他函数来捕获它。

您可以使用expr来实现,不过ShellCheck报告这种用法已弃用。

为了说明我对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]"

不过还是很恶心。

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=

你可以让这个函数把一个变量作为第一个参数,然后用你想要返回的字符串修改变量。

#!/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

你可以使用一个全局变量:

declare globalvar='some string'

string ()
{
  eval  "$1='some other string'"
} # ----------  end of function string  ----------

string globalvar

echo "'${globalvar}'"

这给了

'some other string'