如何從Bash函數返回字符串值

我想從Bash函數返回一個字符串。 shell

我將用Java編寫示例以顯示我想作的事情: 安全

public String getSomeString() {
  return "tadaa";
}

String variable = getSomeString();

下面的示例在bash中有效,可是有更好的方法嗎? bash

function getSomeString {
   echo "tadaa"
}

VARIABLE=$(getSomeString)

#1樓

考慮如下代碼,向Vicky Ronnen擡起頭來: ide

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正確指出的那樣。 性能


#2樓

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=

#3樓

像上面的bstpierre同樣,我使用並建議使用顯式命名輸出變量: this

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時,速度差別彷佛更爲明顯,由於從函數調用捕獲stdout幾乎是災難性的。 spa

能夠發送局部變量,由於局部變量在bash中動態做用域: code

function another_func() # ARG
{
   local result
   some_func result "$1"
   echo result is $result
}

#4樓

正如其餘人所寫,最直接,最可靠的解決方案是使用命令替換: 作用域

assign()
{
    local x
    x="Test"
    echo "$x"
}

x=$(assign) # This assigns string "Test" to x

缺點是性能,由於這須要單獨的過程。

本主題中建議的另外一種技術,即傳遞要分配給變量的變量名稱做爲參數,會產生反作用,我不建議以其基本形式使用它。 問題是您可能須要在函數中使用一些變量來計算返回值,而且可能會發生的是,用於存儲返回值的變量名稱會干擾其中之一:

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

固然,您可能不將函數的內部變量聲明爲局部變量,但實際上應始終這樣作,不然,若是存在一個同名變量,則您可能會意外覆蓋父做用域中不相關的變量。

一種可能的解決方法是將傳遞的變量顯式聲明爲global:

assign()
{
    local x
    eval declare -g $1
    x="Test"
    eval "$1=\$x"
}

若是將名稱「 x」做爲參數傳遞,則函數主體的第二行將覆蓋先前的本地聲明。 可是名稱自己可能仍然會干擾,所以,若是您打算使用先前存儲在傳遞的變量中的值,而後再在其中寫入返回值,請注意,您必須從一開始就將其複製到另外一個局部變量中。 不然結果將不可預測! 此外,這僅適用於最新的BASH版本4.2。 更多可移植的代碼可能會使用具備相同效果的顯式條件構造:

assign()
{
    if [[ $1 != x ]]; then
      local x
    fi
    x="Test"
    eval "$1=\$x"
}

也許最優雅的解決方案只是爲函數返回值保留一個全局名稱,並在您編寫的每一個函數中一致地使用它。


#5樓

如前所述,從函數返回字符串的「正確」方法是使用命令替換。 若是該函數也須要輸出到控制檯(如@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]

但願這能夠幫助人們

-安迪

相關文章
相關標籤/搜索