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