Возвращаемое значение в функции Bash

Я работаю со скриптом bash, и я хочу выполнить функцию для печати возвращаемого значения:

function fun1(){
  return 34
}
function fun2(){
  local res=$(fun1)
  echo $res
}

когда я выполнить fun2, он не печатает "34". Почему это так?

9 ответов


хотя у Баша есть return оператор, единственное, что вы можете указать с ним, это собственная функция exit статус (значение между 0 и 255, 0 означает "успех"). Так что return не то, что вы хотите.

вы можете конвертировать ваш return заявление к echo statement-таким образом, ваш вывод функции может быть захвачен с помощью $() брекеты, которые, кажется, именно то, что вы хотите.

здесь пример:

function fun1(){
  echo 34
}

function fun2(){
  local res=$(fun1)
  echo $res
}

другой способ, чтобы получить возвращаемое значение (если вы просто хотите вернуть целое число 0-255) составляет $?.

function fun1(){
  return 34
}

function fun2(){
  fun1
  local res=$?
  echo $res
}

кроме того, обратите внимание, что вы можете использовать возвращаемое значение для использования логики типа fun1 || fun2 только fun2 если fun1 возвращает 0 значение. Возвращаемое значение по умолчанию-это значение exit последнего оператора, выполненного в функции.


$(...) захватывает текст, отправленный в stdout командой, содержащейся внутри. return не выводится в stdout. $? содержит код результата выполнения последней команды.

fun1 (){
  return 34
}

fun2 (){
  fun1
  local res=$?
  echo $res
}

функции в Bash не являются функциями, как на другом языке; они на самом деле команды. Таким образом, функции используются так, как если бы они были двоичными файлами или скриптами, извлеченными из вашего пути. С точки зрения логики вашей программы не должно быть никакой разницы.

команды оболочки соединяются каналами (aka streams), а не фундаментальными или пользовательскими типами данных, как в "реальных" языках программирования. Нет такой вещи, как возвращаемое значение для команды, может быть, в основном потому, что нет никакого способа заявить об этом. Это может произойти на главной странице, или --help вывод команды, но оба они только читаются человеком и, следовательно, записываются на ветер.

когда команда хочет получить ввод, она считывает его из своего входного потока или списка аргументов. В обоих случаях текстовые строки должны быть проанализированы.

когда команда хочет вернуть что-то, она должна echo it к его выходному потоку. Другой часто практикуемый способ-сохранить возвращаемое значение в выделенные глобальные переменные. Запись в выходной поток более четкая и гибкая, потому что она может принимать также двоичные данные. Например, вы можете легко вернуть BLOB:

encrypt() {
    gpg -c -o-  # encrypt data in filename to stdout (asks for a passphrase)
}

encrypt public.dat > private.dat # write function result to file

как и другие, написанные в этом потоке, вызывающий также может использовать замену команды $() для вывода данных.

параллельно, функция будет возвращать код выхода gpg (GnuPG). Подумайте о коде выхода как о бонусе, которого нет в других языках, или, в зависимости от вашего темперамент, как "Шмуцэффект" функций оболочки. Это состояние, по соглашению, 0 на успех или целое число в диапазоне 1-255 для чего-то еще. Чтобы прояснить это: return (как exit) может принимать значение только от 0-255, а значения, отличные от 0, не обязательно являются ошибками, как это часто утверждается.

когда вы не предоставляете явное значение с return статус берется из последней команды в инструкции/функции/команде Bash и так далее. Так что всегда есть статус, и return это просто простой способ обеспечить его.


на return оператор устанавливает код выхода функции, почти такой же, как exit будет делать для всего скрипта.

код выхода для последней команды всегда доступен в $? переменной.

function fun1(){
  return 34
}

function fun2(){
  local res=$(fun1)
  echo $? # <-- Always echos 0 since the 'local' command passes.

  res=$(fun1)
  echo $?  #<-- Outputs 34
}

мне нравится делать следующее, Если выполняется в скрипте, где определена функция:

POINTER= # used for function return values

my_function() {
    # do stuff
    POINTER="my_function_return"
}

my_other_function() {
    # do stuff
    POINTER="my_other_function_return"
}

my_function
RESULT="$POINTER"

my_other_function
RESULT="$POINTER"

мне это нравится, потому что я могу включить операторы echo в свои функции, если я хочу

my_function() {
    echo "-> my_function()"
    # do stuff
    POINTER="my_function_return"
    echo "<- my_function. $POINTER"
}

в качестве дополнения к отличным сообщениям других, вот статья, обобщающая эти методы:

  • установить глобальную переменную
  • установите глобальную переменную, имя которой вы передали функции
  • установить код возврата (и забрать его с $?)
  • 'echo' некоторые данные (и забрать его с MYVAR=$(myfunction))

возврат значений из функций Bash


проблема с других ответов они либо использовать глобальные, которые могут быть перезаписаны при нескольких функций в цепочке вызовов, или эхо, что означает ваша функция не может выводить диагностическую информацию (вы забудете свои функции и "результат", т. е. возвращаемое значение будет содержать больше сведений, чем ваш собеседник ожидает, что приводит к странной ошибке), или eval, которая так тяжело и замысловато.

правильный способ сделать это-поместить материал верхнего уровня в функцию и использовать локальный с правило динамического обзора Баша. Пример:

func1() 
{
    ret_val=hi
}

func2()
{
    ret_val=bye
}

func3()
{
    local ret_val=nothing
    echo $ret_val
    func1
    echo $ret_val
    func2
    echo $ret_val
}

func3

выводит

nothing
hi
bye

динамическая область видимости означает, что ret_val указывает на другой объект в зависимости от вызывающего абонента! Это отличается от лексической области, которую использует большинство языков программирования. Это на самом деле документированные функции, просто легко пропустить, и не очень хорошо объяснено, вот документы для него (акцент мой):

локальные переменные функции могут быть объявлено с местным встроенный. Эти переменные видны только функции и команды он вызывает.

для кого-то с фоном C/C++/Python/Java/C#/javascript это, вероятно, самое большое препятствие: функции в bash не являются функциями, они являются командами и ведут себя как таковые: они могут выводить в stdout/stderr, они могут вводить/выводить, они могут возвращать код выхода. В принципе нет никакой разницы между определением команда в скрипте и создание исполняемого файла, который может быть вызван из команды.

поэтому вместо того, чтобы писать свой сценарий так:

top-level code 
bunch of functions
more top-level code

написать так:

# define your main, containing all top-level code
main() 
bunch of functions
# call main
main  

где main () объявляет ret_val как local, а все остальные функции возвращают значения через ret_val.

см. также https://unix.stackexchange.com/questions/282557/scope-of-local-variables-in-shell-functions - ...


другой способ достичь этого -название ссылки (требуется Bash 4.3+).

function example {
  local -n VAR=
  VAR=foo
}

example RESULT
echo $RESULT

Git Bash on Windows использование массивов для несколько возвращаемые значения

BASH КОД:

#!/bin/bash

##A 6-element array used for returning
##values from functions:
declare -a RET_ARR
RET_ARR[0]="A"
RET_ARR[1]="B"
RET_ARR[2]="C"
RET_ARR[3]="D"
RET_ARR[4]="E"
RET_ARR[5]="F"


function FN_MULTIPLE_RETURN_VALUES(){

   ##give the positional arguments/inputs
   ## and  some sensible names:
   local out_dex_1="" ##output index
   local out_dex_2="" ##output index

   ##Echo for debugging:
   echo "running: FN_MULTIPLE_RETURN_VALUES"

   ##Here: Calculate output values:
   local op_var_1="Hello"
   local op_var_2="World"

   ##set the return values:
   RET_ARR[ $out_dex_1 ]=$op_var_1
   RET_ARR[ $out_dex_2 ]=$op_var_2
}


echo "FN_MULTIPLE_RETURN_VALUES EXAMPLES:"
echo "-------------------------------------------"
fn="FN_MULTIPLE_RETURN_VALUES"
out_dex_a=0
out_dex_b=1
eval $fn $out_dex_a $out_dex_b  ##<--Call function
a=${RET_ARR[0]} && echo "RET_ARR[0]: $a "
b=${RET_ARR[1]} && echo "RET_ARR[1]: $b "
echo
##----------------------------------------------##
c="2"
d="3"
FN_MULTIPLE_RETURN_VALUES $c $d ##<--Call function
c_res=${RET_ARR[2]} && echo "RET_ARR[2]: $c_res "
d_res=${RET_ARR[3]} && echo "RET_ARR[3]: $d_res "
echo
##----------------------------------------------##
FN_MULTIPLE_RETURN_VALUES 4 5  ##<---Call function
e=${RET_ARR[4]} && echo "RET_ARR[4]: $e "
f=${RET_ARR[5]} && echo "RET_ARR[5]: $f "
echo
##----------------------------------------------##


read -p "Press Enter To Exit:"

ОЖИДАЕМЫЙ РЕЗУЛЬТАТ:

FN_MULTIPLE_RETURN_VALUES EXAMPLES:
-------------------------------------------
running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[0]: Hello
RET_ARR[1]: World

running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[2]: Hello
RET_ARR[3]: World

running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[4]: Hello
RET_ARR[5]: World

Press Enter To Exit: