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



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



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


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

746   9  

9 ответов:

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

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

вот это пример:

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 возвращает a 0 значение. Возвращаемое значение по умолчанию-это выходное значение последнего оператора, выполненного в функции.

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

fun1 (){
  return 34
}

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

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

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

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

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

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 это просто простой способ обеспечить его.

The 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"

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

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

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

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

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

проблема с другими ответами заключается в том, что они либо используют глобальный, который может быть перезаписан, когда несколько функций находятся в цепочке вызовов, либо echo, что означает, что ваша функция не может выводить диагностическую информацию (вы забудете, что ваша функция делает это, и "результат", т. е. возвращаемое значение, будет содержать больше информации, чем ожидает ваш вызывающий, что приводит к странной ошибке), или 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 локальным, а все остальные функции возвращают значения через 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:

Comments

    Ничего не найдено.