728x90
[Shell Script] 스크립트에서 환경 변수가 적용되지 않는 경우
이번에 gitlab CI/CD를 수정하는 업무를 하면서 스크립트를 수정하는 과정에서 while 문 내부에서 정의한 환경 변수를 루프 외부에서도 사용하려고 하니 예상과 다르게 환경 변수값이 사라지는 문제가 발생했다.
이번 포스팅에선 해당 문제의 원인과 해결 방법에 대해 알아보고자 한다.
문제 상황
다음과 같은 스크립트를 작성했다고 가정해보자.
info="1234 **KEY1**
5678 **KEY2**"
echo "$info" | while read -r line; do
if [[ $line =~ ([0-9]+)\ \*\*([A-Z]+)\*\* ]]; then
export "${BASH_REMATCH[2]}=${BASH_REMATCH[1]}
fi
done
echo "KEY1=$KEY1"
echo "KEY2=$KEY2"
위 코드에서 while문 내부에서 export로 변수를 설정했으므로, 루프가 종료된 후에도 `$KEY1`과 `$KEY2`가 유효 할 것이라고 기대하지만, 실행 결과는 다음과 같다.
KEY1=
KEY2=
이 문제는 Bash의 서브쉘(subshell) 동작과 관련이 있다.
💡 서브쉘(subshell)
서브쉘은 현재 실행 중인부모 쉘에서 생성된 별도의 하위 쉘 환경이다.
서브쉘은 부모쉘의 환경을 복사하여 실행되지만, 서브쉘에서 발생한 변화(ex. 변수설정, 디렉토리 변경 등)는 부모 쉘에는 영향을 미치지 않는다.
서브쉘은 파이프`|`, 백그라운드 실행`&`, 명령 그룹`()` 등을 사용하게 되면 서브쉘 환경에서 실행하게 된다.
위 스크립트에서는 파이프`|`로 인해 while 루프가 서브쉘에서 실행되어 해당 루프에서 정의한 변수가 부모쉘에 영향을 주지 않으므로 값이 사라지게 되는 것이었다.
해결 방법
1. 프로세스 서브스티튜션 `<()`
파이프 대신 `<()` 를 사용하면 서브쉘 문제를 피할 수 있다.
info="1234 **KEY1**
5678 **KEY2**"
while read -r line; do
if [[ $line =~ ([0-9]+)\ \*\*([A-Z]+)\*\* ]]; then
export "${BASH_REMATCH[2]}=${BASH_REMATCH[1]}
fi
done < <(echo -e "$info")
echo "KEY1=$KEY1"
echo "KEY2=$KEY2"
#결과
KEY1=1234
KEY2=1234
2. eval
`eval`로 부모 쉘에 변수를 직접 설정한다.
info="1234 **KEY1**
5678 **KEY2**"
echo -e "$info" | while read -r line; do
if [[ $line =~ ([0-9]+)\ \*\*([A-Z]+)\*\* ]]; then
eval "${BASH_REMATCH[2]}=${BASH_REMATCH[1]}
fi
done
echo "KEY1=$KEY1"
echo "KEY2=$KEY2"
❗ `eval` 은 보안상 위험할 수 있으므로 권장하지 않는 방법이다.
3. 임시 파일을 활용
루프 내에서 변수 값을 임시 파일에 저장하고, 루프 종료 후 해당 값을 읽어오는 방법이다.
info="1234 **KEY1**
5678 **KEY2**"
tmpfile=$(mktemp)
echo -e "$info" | while read -r line; do
if [[ $line =~ ([0-9]+)\ \*\*([A-Z]+)\*\* ]]; then
echo "${BASH_REMATCH[2]}=${BASH_REMATCH[1]} >> "$tmpfile"
fi
done
source "$tmpfile"
rm -f "$tmpfile"
echo "KEY1=$KEY1"
echo "KEY2=$KEY2"
4. 함수를 활용한 간접 접근
while 루프를 함수로 감싸고, 부모 프로세스에 변수를 전달한다.
info="1234 **KEY1**
5678 **KEY2**"
process_lines() {
while read -r line; do
if [[ $line =~ ([0-9]+)\ \*\*([A-Z]+)\*\* ]]; then
export "${BASH_REMATCH[2]}=${BASH_REMATCH[1]}
fi
done
}
echo -e "$info" | process_lines
echo "KEY1=$KEY1"
echo "KEY2=$KEY2"
반응형
'🌏 OS > Linux' 카테고리의 다른 글
[Shell Script] 한 줄씩 처리하기 (0) | 2025.01.14 |
---|---|
[Shell Script] 쉘에서 정규표현식 사용하기 (0) | 2025.01.13 |
[Linux] awk (0) | 2024.08.07 |
[Linux] 파일 시간 확인하기 (0) | 2024.08.02 |
[Linux] bash에서 yaml 파일 load하기 (0) | 2024.07.18 |