ice rabbit programming

[bash] bash 파일에서 값 반환(return)하기 본문

Development/Scripts

[bash] bash 파일에서 값 반환(return)하기

판교토끼 2021. 1. 28. 02:04

최근 Jenkins에서 bash 파일을 실행하고, 그 결과 값을 이용할 필요가 있었다.

값 반환하기(기본)

값 반환(return value)은 특이하게도 echo, printf 등 stdout 출력으로 할 수 있었다(참고 : echo와 printf는 거의 동일하나, echo는 끝에 개행문자(\n)가 자동으로 붙고, printf가 좀 더 다양한 표현을 쓸 수 있다).

RESULT=$(curl -X GET https://my_url) # curl 결과를 RESULT에 담음
echo "${RESULT}" # RESULT stdout에 담아 반환

 

모든 echo가 반환되는 이슈

문제는 보통 스크립트 파일을 작성할 때에는, 진행 과정 및 정보를 알고자 로그를 출력으로 남기는 일이 잦다는 것이다(return value with print log). 예를 들면 아래와 같다.

echo "curl request start"
RESULT=$(curl -X GET https://my_url) # curl 결과를 RESULT에 담음
echo "${RESULT}" # RESULT stdout에 담아 반환

 

첫 줄의 echo는 출력만을 위한 줄이고, 마지막 줄의 echo는 반환을 위한 echo이다. 하지만 이것이 구분되지 않고, 실행할 때에 한꺼번에 반환되는 것이 이슈였다. stdout에 담긴 것 자체가 반환되기 때문에, printf로 바꾸어도 똑같은 이슈가 발생한다.

BASH_RESULT=$(bash ./test.sh) # curl request start와 RESULT 변수 값이 string으로 연결되어 나온다.

 

BASH_RESULT에서 bash 파일에서 사용한 echo들이 모두 출력되는 문제가 발생하였다. 또한, echo가 한 번에 반환되다 보니 로그가 찍혀야할 시점에 찍히지 않고, BASH_RESULT에 담겨버렸다. 즉, curl이 다 끝나고 curl request start가 출력되는 것.

 

해결법 1. tail을 사용

결국 마지막 echo만을 반환 값으로 사용한다면, tail -1을 사용하는 방법이 있다.

BASH_RESULT=$(bash ./test.sh | tail -1)
# 혹은 | tail -n1. 필자는 위 명령어로 되었는데 안 되는 경우는 아래를 시도해보길

 

이렇게 하면 원래의 의도대로 마지막 RESULT를 echo한 값만 담긴다. 값도 잘 사용 가능하다. 하지만 이전에 로깅을 위해 찍었던 echo들이 모두 무시되어 출력되지 않는 이슈가 있었다.

 

해결법 2. stderr을 사용

올바른 방법은 아니라고 생각하지만 로깅을 위한 echo는 stderr로 출력하고, 반환을 위한 echo는 stdout으로 보내는 것이다.

echo "curl request start" >&2 # stderr로 보낸다.
RESULT=$(curl -X GET https://my_url) # curl 결과를 RESULT에 담음
echo "${RESULT}" # RESULT stdout에 담아 반환

 

이렇게 하면 bash 파일을 실행한 쪽에 로그도 정상적으로 찍히고 반환한 값도 이용할 수 있다.

 

(번외) 시도해봤던 방법

함수 내에서 실행한 echo는 밖으로 새지 않는다는 글이 있었다. 함수에서의 반환도 echo를 사용하는데, 이 또한 로그 출력과 겹칠 수 있으므로 전역 변수를 사용하였다. 참고로 함수 반환에서 return을 쓰는 경우도 발견할 수 있는데, 이는 값 반환을 위함이 아니라 함수의 성공/실패 여부를 전달하기 위한 1바이트 정수로, 0~255 값만 return 가능하다.

GLOBAL_RESULT=''
get_test () {
    echo "curl request start"
    RESULT=$(curl -X GET https://my_url) # curl 결과를 RESULT에 담음
    GLOBAL_RESULT=RESULT # RESULT를 전역 변수에 담음
}

get_test
echo "${GLOBAL_RESULT}"

 

이런 식으로 구성하는 방법이었는데, 시도해보니 함수 내에서 사용한 echo도 stdout에 담기기 때문에 반환이 함께 되는 이슈는 해결되지 않았다.

결론적으로 2번의 stderr을 사용하는 방법을 통해 해결은 했으나, 어쨌거나 로그 자체는 error가 아니므로 완벽한 해결이라는 생각은 들지 않는다. 하지만 구글링을 해보아도 마땅한 해결법을 찾기 어려워서 일단은 기능상으로 두 가지 모두를 얻을 수 있는 stderr을 사용하였다.

한글로 정리된 곳도 없고, 영어로 된 글들도 여러 군데를 돌아다녀야 얻을 수 있는 정보라 정리하였다.