쉘 스크립트에서 호출 된 함수의 값 반환


126

쉘 스크립트에서 호출 된 함수에서 값을 반환하고 싶습니다. 아마도 구문이 누락되었습니다. 전역 변수를 사용해 보았습니다. 그러나 그것은 또한 작동하지 않습니다. 코드는 다음과 같습니다.

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

질문과 관련이 없지만 어쨌든 ... 잠금을 얻으려는 경우 "lockfile"명령을 사용할 수 있습니다.
Víctor Herraiz 2014

답변:


277

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

2
functionbash 함수를 정의하는 데 키워드를 사용하지 마십시오 . 그러면 휴대 성이 떨어집니다. 그것을 제거합니다.
dimir

2
세 번째 예에서 retval은 환경 변수가 아닙니다. 단지 쉘 변수 일뿐입니다. 내보내는 경우에만 환경 변수가됩니다. 세 번째 예제의 제목은 "환경 변수"대신 "전역 변수"여야합니다.
William Pursell 2012 년

4
두 번째 예에서는, 오히려 $에서 할당하는 것보다? 그것은 "만약 testlock 후 ..."쓰기에 더 관용적이다
윌리엄 Pursell

@WilliamPursell 잘못된 '환경'단어를 제거했습니다. 계속 "$?" 교육 목적을 위해. Wiki 커뮤니티를 활성화 했으므로 답변을 개선 할 수 있습니다. ;-)
olibre

1
@ManuelJordan, 함수는 종료 코드와> & 2 로그 만 stderror에 반환 할 수 있으므로 마지막 에코는 stdout에 기록되므로 호출 함수는 stderr가 아닌 stdout 만 캡처합니다. 실행이 단일 스레드라고 가정 할 때 더 나은 옵션은 testlock을 호출 한 후 누구나 사용할 수있는 TEST_LOCK_STATUS = ""외부 메서드와 같은 특정 사용자 지정 변수를 유지하고 메서드 시작 시마다 재설정하는 것입니다
kisna

16

당신은 너무 열심히 일하고 있습니다. 전체 스크립트는 다음과 같아야합니다.

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

그러나 그것조차 아마 너무 장황 할 것입니다. 나는 그것을 코딩 할 것이다 :

mkdir "$lockdir" || exit 1

그러나 결과 오류 메시지는 약간 모호합니다.


1
누락 된 오류 메시지는 약간 더 장황하지만 쉽게 수정할 수 있습니다. mkdir "$lockdir" || { echo "could not create lock dir" >&2 ; exit 1 ; }( ;닫는 중괄호 앞을 참고하십시오 ). 또한 stderr에 인쇄 한 다음 반환 코드 1과 함께 종료되는 선택적 메시지 매개 변수를 사용하는 실패 함수를 정의하여 더 읽기 쉬운 mkdir "$lockdir" || fail "could not create lock dir".
blubberdiblub

@blubberdiblub :하지만 실패 함수는 "현재"함수 나 스크립트를 종료 할 수 없습니까? 그러려면 그렇게하려면 사용해야 cmd || fail "error msg" || return 1하죠?
최대

@Max는 현재 기능이 아닙니다. 그러나 명령으로 호출하고 소싱하지 않는 한 현재 스크립트를 종료 합니다. 나는 보통 fail치명적인 상황에서만 사용되는 그런 기능을 생각 합니다.
blubberdiblub

12

단지 참 / 거짓 테스트라면 return 0성공과 return 1실패를위한 기능 을 갖추십시오 . 테스트는 다음과 같습니다.

if function_name; then
  do something
else
  error condition
fi

내가 찾던 바로 그것.
사무엘

매개 변수화 된 함수에도이 표기법을 사용하는 방법이 있습니까?
알렉스

@alex "매개 변수화 된 함수"가 의미하는 바의 예를 들어 줄 수 있습니까?
글렌 잭맨

'myCopyFunc $ {SOURCE} $ {DEST}', 성공하면 0을 반환합니다. 예 :이 문제에 같은 : stackoverflow.com/questions/6212219/...
알렉스

네, 완벽하게 괜찮아요
글렌 잭맨

2

나는 실패 (glenn jackman)에 대해 succ / 1에 대해 0을 반환한다고 생각하고 olibre의 명확하고 설명적인 대답은 모든 것을 말합니다. 결과가 바이너리가 아니고 결과를 "반향"하는 것보다 변수를 설정하는 것을 선호하는 경우에 대한 일종의 "콤보"접근 방식을 언급하기 만하면됩니다 (예를 들어 함수가 무언가를 에코한다고 가정하면이 접근 방식은 작동하지). 그럼 뭐야? (아래는 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

1

함수에 전달할 매개 변수가 있고 값을 반환하려는 경우. 여기서는 "12345"를 함수에 대한 인수로 전달하고 VALUE에 할당 될 반환 변수 XYZ를 처리 한 후

#!/bin/bash
getValue()
{
    ABC=$1
    XYZ="something"$ABC
    echo $XYZ
}


VALUE=$( getValue "12345" )
echo $VALUE

산출:

something12345
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.