Возвращение значения из вызываемой функции в сценарии оболочки - PullRequest
109 голосов
/ 05 января 2012

Я хочу вернуть значение из функции, вызываемой в сценарии оболочки. Возможно, мне не хватает синтаксиса. Я пытался использовать глобальные переменные. Но это тоже не работает. Код:

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

Ответы [ 4 ]

236 голосов
/ 05 января 2012

Функция Bash не может вернуть строку напрямую, как вы этого хотите.Вы можете сделать три вещи:

  1. Вывести строку
  2. Вернуть состояние выхода, которое является числом, а не строкой
  3. Поделиться переменной

Это также верно для некоторых других оболочек.

Вот как выполнить каждый из этих параметров:

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
15 голосов
/ 05 января 2012

Вы слишком усердно работаете.Весь ваш сценарий должен быть:

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

, но даже это, вероятно, слишком многословно.Я бы кодировал это:

mkdir $lockdir || exit 1

, но полученное сообщение об ошибке немного неясно.

11 голосов
/ 05 января 2012

Если это просто проверка на истинность / ложь, используйте вашу функцию return 0 для успеха и return 1 для неудачи.Тогда тест будет:

if function_name; then
  do something
else
  error condition
fi
2 голосов
/ 15 декабря 2016

Я думаю, что возвращение 0 для succ / 1 для неудачи (Гленн Джекман) и ясный и понятный ответ Олибре говорит само за себя; просто упомянуть своего рода «комбинированный» подход для случаев, когда результаты не являются двоичными, и вы бы предпочли установить переменную, а не «выводить» результат (например, если ваша функция ТАКЖЕ предполагает что-то повторить, этот подход не работа). Что тогда? (ниже Bourne Shell)

# 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
...