从Shell脚本中的被调用函数返回值


126

我想从外壳程序脚本中调用的函数返回值。也许我缺少语法。我尝试使用全局变量。但这也不起作用。代码是:

lockdir="somedir"
test() {
    retval=""

    if mkdir "$lockdir"
        then    # Directory did not exist, but it was created successfully
            echo >&2 "successfully acquired lock: $lockdir"
            retval="true"
        else
            echo >&2 "cannot acquire lock, giving up on $lockdir"
            retval="false"
    fi
    return retval
}


retval=test()
if [ "$retval" == "true" ]
    then
        echo "directory not created"
    else
        echo "directory already created"
fi

与您的问题无关,但是无论如何...如果您试图获取锁,则可以使用“ lockfile”命令。
维克托·赫雷兹(VíctorHerraiz)2014年

Answers:


277

Bash函数无法像您想要的那样直接返回字符串。您可以做三件事:

  1. 回声字符串
  2. 返回退出状态,它是一个数字,而不是字符串
  3. 共享变量

对于其他一些shell也是如此。

这是每个选项的操作方法:

1.回声弦

lockdir="somedir"
testlock(){
    retval=""
    if mkdir "$lockdir"
    then # Directory did not exist, but it was created successfully
         echo >&2 "successfully acquired lock: $lockdir"
         retval="true"
    else
         echo >&2 "cannot acquire lock, giving up on $lockdir"
         retval="false"
    fi
    echo "$retval"
}

retval=$( testlock )
if [ "$retval" == "true" ]
then
     echo "directory not created"
else
     echo "directory already created"
fi

2.返回退出状态

lockdir="somedir"
testlock(){
    if mkdir "$lockdir"
    then # Directory did not exist, but was created successfully
         echo >&2 "successfully acquired lock: $lockdir"
         retval=0
    else
         echo >&2 "cannot acquire lock, giving up on $lockdir"
         retval=1
    fi
    return "$retval"
}

testlock
retval=$?
if [ "$retval" == 0 ]
then
     echo "directory not created"
else
     echo "directory already created"
fi

3.分享变量

lockdir="somedir"
retval=-1
testlock(){
    if mkdir "$lockdir"
    then # Directory did not exist, but it was created successfully
         echo >&2 "successfully acquired lock: $lockdir"
         retval=0
    else
         echo >&2 "cannot acquire lock, giving up on $lockdir"
         retval=1
    fi
}

testlock
if [ "$retval" == 0 ]
then
     echo "directory not created"
else
     echo "directory already created"
fi

2
不要使用function关键字定义bash函数。那将使它的可移植性降低。删除它。
dimir,2012年

2
在第三个示例中,retval不是环境变量。它仅仅是一个shell变量。如果将其导出,它将仅成为环境变量。也许第三个示例的标题应该是“全局变量”而不是“环境变量”。
William Pursell 2012年

4
在第二个示例中,不是从$?赋值,而是写成“ if testlock; then ...”
William Pursell

@WilliamPursell我删除了错误的“环境”一词。让我们保持“ $?” 用于教学目的。我已经启用了Wiki社区,因此你们所有人都可以自由地改善答案;-)
olibre 2012年

1
@ManuelJordan,函数只能将退出代码和>&2日志返回到stderror,因此,最后一个回显将写入stdout,因此,调用函数仅捕获stdout而不捕获stderr。假设执行是单线程的,一个更好的选择是维护一个特定于自定义变量的变量,例如TEST_LOCK_STATUS =“”,任何人都可以在调用testlock之后使用该方法,并在每次方法启动时将其重置
kisna

16

你工作太辛苦了。您的整个脚本应为:

if mkdir "$lockdir" 2> /dev/null; then 
  echo lock acquired
else
  echo could not acquire lock >&2
fi

但这甚至太冗长了。我会编码:

mkdir "$lockdir" || exit 1

但是产生的错误消息有点模糊。


1
丢失的错误消息很容易修复,即使它有些冗长:(mkdir "$lockdir" || { echo "could not create lock dir" >&2 ; exit 1 ; }请注意;右花括号前的)。此外,我经常定义一个故障函数,该函数带有一个可选的message参数,该参数将打印到stderr,然后以返回代码1退出,使我能够使用更具可读性的mkdir "$lockdir" || fail "could not create lock dir"
blubberdiblub '16

@blubberdiblub:但fail函数不能退出“当前”函数或脚本,可以吗?所以cmd || fail "error msg" || return 1如果您想这样做,就必须使用,是吗?
最多

@Max不是当前函数,那是正确的。但是,只要您将其作为命令调用且未提供它,它将退出当前脚本。我通常认为这种fail功能仅用于致命情况。
blubberdiblub

12

如果这只是一个对/错的测试,那么请发挥return 0成功和return 1失败的作用。测试将是:

if function_name; then
  do something
else
  error condition
fi

正是我想要的。
塞缪尔

是否可以对参数化函数使用此表示法?
Alex

@alex您可以举一个例子说明“参数化函数”的含义吗?
格伦·杰克曼

'myCopyFunc $ {SOURCE} $ {DEST}',成功返回0。例如,像本期这样:stackoverflow.com/questions/6212219/…–
Alex

是的,那很好
格伦·杰克曼

2

我认为为succ / 1返回0表示失败(格伦·杰克曼),而olibre清晰而有说服力的答案说明了一切。仅提及一种针对结果不是二进制的情况的“组合”方法,您宁愿设置变量而不是“回显”结果(例如,如果您的函数还假设是回显某些内容,则该方法将不行)。然后怎样呢?(下面是《伯恩·壳》)

# Syntax _w (wrapReturn)
# arg1 : method to wrap
# arg2 : variable to set
_w(){
eval $1
read $2 <<EOF
$?
EOF
eval $2=\$$2
}

如(是的,示例有点愚蠢,这只是一个示例。)

getDay(){
  d=`date '+%d'`
  [ $d -gt 255 ] && echo "Oh no a return value is 0-255!" && BAIL=0 # this will of course never happen, it's just to clarify the nature of returns
  return $d
}

dayzToSalary(){
  daysLeft=0
  if [ $1 -lt 26 ]; then 
      daysLeft=`expr 25 - $1`
  else
     lastDayInMonth=`date -d "`date +%Y%m01` +1 month -1 day" +%d`
     rest=`expr $lastDayInMonth - 25`
     daysLeft=`expr 25 + $rest`
  fi
  echo "Mate, it's another $daysLeft days.."
}

# main
_w getDay DAY # call getDay, save the result in the DAY variable
dayzToSalary $DAY

1

如果您有一些参数要传递给函数,并希望返回一个值。在这里,我将“ 12345”作为参数传递给函数,并在处理完返回变量XYZ后将其分配给VALUE

#!/bin/bash
getValue()
{
    ABC=$1
    XYZ="something"$ABC
    echo $XYZ
}


VALUE=$( getValue "12345" )
echo $VALUE

输出:

something12345
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.