Bash 함수의 반환 값


305

bash 스크립트로 작업 중이며 반환 값을 인쇄하는 함수를 실행하려고합니다.

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

내가 실행할 때 fun2 "34"가 인쇄되지 않습니다. 왜 이런 경우입니까?


8
return귀하의 경우 기본적으로의 exit code범위 와 동일 0 - 255합니다. echo@septi가 제안한대로 사용하십시오 . 로 종료 코드를 캡처 할 수 있습니다 $?.
devnull

1
이 경우 fun1에서 이미 echo를 사용하는 것이 훨씬 더 유연합니다. 그것은 유닉스 프로그래밍의 아이디어이다 : echo는 결과를 표준 출력으로 보낸 다음 res = $ (fun1)로 다른 함수에 의해 재사용되거나 다른 함수로 직접 파이프 될 수있다 :function a() { echo 34; } function b() { while read data; do echo $data ; done ;} a | b
Arne Babenhauserheide

이를 수행하는 올바른 방법은 최상위 레벨 항목을 함수에 넣고 bash의 동적 범위 지정 규칙을 사용하여 로컬을 사용하는 것입니다. 잘 알려진 기능은 아니지만 완전히 지원되는 기능을 보여주기 위해 답변을 작성하겠습니다.
Oliver


답변:


373

bash는 return문장을 가지고 있지만 , 이것으로 지정할 수있는 유일한 것은 함수의 자체 exit상태 ( 0255성공 사이의 0 과 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되는 것처럼 부울 논리를 사용하기 위해 반환 값을 사용할 수 있습니다 . 디폴트 리턴 값은 함수 내에서 마지막으로 실행 된 명령문의 종료 값입니다.fun10


2
실행 fun1한 다음 반환 값이에 저장됩니다 $?. 나는 그렇게하지 않는 것이 좋지만…
tamasgal

9
왜 사용하지 $?않습니까?
Pithikos

147
아니요, 젠장 반환 값이 필요합니다 . 반향으로 지옥에.
Tomáš Zato-복직 모니카

7
이 환경에서 @Blauhirn은이 ||구성으로 종료 코드 0이 성공으로 간주되므로 "참"으로 간주됩니다. 0이 아닌 것은 오류이므로 거짓입니다. fun1 || fun2실제 리턴 값 자체에 대한 연산자가 아니라 "fun1이 성공을 리턴하거나 fun2가 성공을 리턴하는 경우"의 약어로 생각하십시오 .
davidA

6
성가신 것은 데이터를 제공 해야하는 함수가 $ ()를 사용하는 호출자가 그것을 수신하고 혼란스러워하거나 출력을 구문 분석해야하기 때문에 stdout에 다른 것을 에코 할 수 없다는 것입니다. 전역 변수는 중첩이 일어나고 데이터가 손실 될 수있는 두 곳에서 동일한 전역 변수를 사용하기 전에 시간 문제이기 때문에 좋지 않습니다. 데이터 인쇄와 데이터 전송을위한 별도의 채널이 있어야합니다.
Oliver

68

$(...)안에 포함 된 명령으로 stdout으로 전송 된 텍스트를 캡처합니다. returnstdout으로 출력하지 않습니다. $?마지막 명령의 결과 코드를 포함합니다.

fun1 (){
  return 34
}

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

6
예는를 return설정 $?하는 데 사용됩니다 exit status. 위의 예에서, fun1의는 exit status것입니다 34. 또한 $(...)지정된 명령의 stdout 외에 stderr도 캡처합니다.
swoop81

59

Bash의 함수는 다른 언어와 같은 함수가 아닙니다. 그들은 실제로 명령입니다. 따라서 함수는 마치 경로에서 가져온 바이너리 또는 스크립트 인 것처럼 사용됩니다. 프로그램 로직의 관점에서 보면 아무런 차이가 없어야합니다.

쉘 명령은 "실제"프로그래밍 언어에서와 같이 기본 또는 사용자 정의 데이터 유형이 아닌 파이프 (일명 스트림)로 연결됩니다. 명령의 반환 값과 같은 것은 없습니다. 주로 그것을 선언하는 실제 방법이 없기 때문일 수 있습니다. 맨 페이지 또는 --help명령 출력에서 발생할 수 있지만 둘 다 사람이 읽을 수 있으므로 바람에 기록됩니다.

명령이 입력을 받으려면 입력 스트림 또는 인수 목록에서 명령을 읽습니다. 두 경우 모두 텍스트 문자열을 구문 분석해야합니다.

명령이 무언가를 반환하려고 할 때 echo출력 스트림에 있어야합니다. 자주 사용되는 또 다른 방법은 반환 값을 전용 전역 변수에 저장하는 것입니다. 출력 스트림에 쓰는 것은 바이너리 데이터도 필요로하기 때문에보다 명확하고 유연합니다. 예를 들어, BLOB을 쉽게 리턴 할 수 있습니다.

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

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

다른 사람들이이 스레드에서 작성했듯이 호출자는 명령 대체 $()를 사용 하여 출력을 캡처 할 수도 있습니다 .

병렬로, 함수는 gpg(GnuPG) 의 종료 코드를 "반환"합니다 . 종료 코드를 다른 언어에없는 보너스 또는 기질에 따라 쉘 기능의 "Schmutzeffekt"로 생각하십시오. 이 상태는 일반적으로 성공시 0 또는 1-255 범위의 정수입니다. 이를 명확하게하기 위해 return(와 같은 exit)는 0-255의 값만 취할 수 있으며 0 이외의 값은 종종 주장되는 것처럼 오류가 아닙니다.

명시적인 값을 제공하지 않으면 return상태는 Bash 문 / 함수 / 명령 등의 마지막 명령에서 가져옵니다. 따라서 항상 상태 return가 있으며이를 제공하는 쉬운 방법 일뿐입니다.


4
기능 대 명령 및 이것이 호출자에게 데이터를 다시 보내는 개념에 미치는 영향에 대해 설명하는 +1
Oliver

4
쉘 프로그래밍이 파이프를 통한 명령 연결에 관한 것임을 설명하기위한 +1 다른 프로그래밍 언어는 리턴 유형을 통해 함수를 구성합니다. Bash는 텍스트 스트림을 통해 명령을 구성합니다.
jrahhali

29

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
}

20

다른 답변의 문제는 전역을 사용 echo한다는 것입니다.이 함수는 호출 체인에 여러 함수가있을 때 덮어 쓸 수 있거나 함수가 진단 정보를 출력 할 수 없다는 것을 의미합니다 (함수는이 기능을 수행하지 않고 "결과"를 반환합니다. 가치, 발신자가 기대하는 것보다 많은 정보를 포함하여 이상한 버그로 이어 지거나 eval너무 무겁고 해킹 적입니다.

이를 수행하는 올바른 방법은 최상위 레벨 항목을 함수에 넣고 localwith bash의 동적 범위 지정 규칙을 사용하는 것 입니다. 예:

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 ++ / 파이썬 / 자바 / C #을 / 자바 스크립트 배경을 가진 사람의 경우, 이것은 가장 큰 장애물은 아마도 : bash는 함수는 명령하고, 같은 행동, 기능하지 않은 : 그들은 출력 할 수 stdout/ stderr, 그들은 파이프에서와 수 / out, 종료 코드를 반환 할 수 있습니다. 기본적으로 스크립트에서 명령을 정의하는 것과 명령 줄에서 호출 할 수있는 실행 파일을 만드는 것에는 차이가 없습니다.

따라서 다음과 같이 스크립트를 작성하는 대신

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  

여기서 as를 main()선언 하고 다른 모든 함수 는 ret_vallocal통해 값을 반환합니다 ret_val.

다음 유닉스 및 리눅스 질문 : 셸 함수의 로컬 변수 범위를 참조하십시오 .

상황에 따라 더 나은 솔루션 중 하나 는 ya.teck게시 한 솔루션 입니다 local -n.


17

이를 달성하는 또 다른 방법은 이름 참조입니다 (Bash 4.3 이상 필요).

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

example RESULT
echo $RESULT

3
무엇을하는지 궁금해하는 사람 -n <name>=<reference>: 새로 작성된 변수를 가리키는 다른 변수에 대한 참조를 만듭니다 <reference>. <name>참조 된 변수에 대한 추가 지정 이 수행됩니다.
Valerio

7

함수가 정의 된 스크립트에서 실행하는 경우 다음을 수행하고 싶습니다.

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

5

다른 사람의 훌륭한 게시물에 대한 추가 기능으로 다음은 이러한 기술을 요약 한 기사입니다.

  • 전역 변수를 설정
  • 함수에 이름을 전달한 전역 변수를 설정하십시오.
  • 리턴 코드를 설정하고 $?
  • 일부 데이터를 '에코'(및 MYVAR = $ (myfunction)로 선택)

Bash 함수에서 값 반환


이 기사는 모든 옵션에 대해 명확하게 논의하기 때문에 가장 좋은 대답입니다.
mzimmermann

-2

여러 반환 값에 배열을 사용 하는 Windows의 Git 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
   ##$1 and $2 some sensible names:
   local out_dex_1="$1" ##output index
   local out_dex_2="$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:
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.