회사에서 crontab으로 쉘 스크립트를 작업하던 중, 예상대로 실행되지 않아 많은 어려움을 겪었습니다.
구글링을 통해 찾아보니, crontab에서는 환경이 다르기 때문에 설정을 해줘야 한다는 내용의 글들을 보았지만, 실제로 로그를 확인해 본 결과 다른 이유가 원인이라는 것을 알게 되었습니다.
아래는 문제 상황을 재현한 간단한 스크립트입니다.
#!/bin/bash
# 부모 셸에서 변수 선언 (export하지 않음)
password="1234"
# 서브 셸에서 my_var 출력 시도
bash -c 'echo "password: $password"'
이 스크립트를 실행하면 결과는 다음과 같이 비어 있는 출력입니다.
password:
이유는 간단합니다.
스크립트에서 작성한 password 변수는 자식 쉘이나 프로세스에 전달되지 않기 때문입니다.
이를 아래와 같이 변경하면 원하는 결과를 얻을 수 있습니다.
#!/bin/bash
# 부모 셸에서 변수 선언 (export하지 않음)
export password="1234"
# 서브 셸에서 my_var 출력 시도
bash -c 'echo "password: $password"'
password: 1234
설명: password=1234로 지정한 경우, 해당 변수는 현재 셸에만 적용되므로 서브 셸에서는 인식되지 않습니다. 그러나 export를 사용해 password를 환경 변수로 만들면, 해당 셸의 하위 프로세스(서브 셸)에서도 이 값을 인식할 수 있어 변수가 전달됩니다.
실제 문제로 겪었던 스크립트는 아래와 같습니다.
PGPASSWORD=...
psql -h ...
처음에는 ./psql-connect.sh처럼 직접 스크립트를 실행했기에 문제가 없었습니다. 그러나 crontab에 추가하고 나서는 다른 상황이 발생했습니다.
echo $PGPASSWORD 결과: 1234크론탭에서는 기존 환경 변수 값이 적용되지 않으므로, 크론탭의 환경과 로그인 셸의 환경이 다르다는 것을 알게 되었습니다.
bashrc에 export local3="local 3333333333" 추가 -> 이를 통해 환경 변수 값을 cronjob 실행시 읽어오는지를 확인
crontab에 추가한 스크립트는 다음과 같습니다.
#!/bin/bash
local1="local 1111111111"
export local2="lcoal 2222222222"
echo "local1: $local1"
echo "local2: $local2"
echo "local3: $local3"
Oct 30 12:26:01 test-vm CROND[4441]: (testuser) CMDOUT (local1: local 1111111111)
Oct 30 12:26:01 test-vm CROND[4441]: (testuser) CMDOUT (local2: lcoal 2222222222)
Oct 30 12:26:01 test-vm CROND[4441]: (testuser) CMDOUT (local3: )
여기서, local3 변수는 crontab 환경에서 적용되지 않았습니다.
crontab에서 초기화 파일을 직접 소스하여 변수를 적용했습니다.
#!/bin/bash
# .bashrc 파일을 소스하여 환경 변수 로드
. ~/.bashrc
local1="local 1111111111"
export local2="lcoal 2222222222"
echo "local1: $local1"
echo "local2: $local2"
echo "local3: $local3"
Oct 30 12:45:01 test-vm CROND[12429]: (testuser) CMDOUT (local1: local 1111111111)
Oct 30 12:45:01 test-vm CROND[12429]: (testuser) CMDOUT (local2: lcoal 2222222222)
Oct 30 12:45:01 test-vm CROND[12429]: (testuser) CMDOUT (local3: lcoal 3333333333333333333333)
이제 local3 변수도 정상적으로 출력되는 것을 확인할 수 있었습니다.
crontab에서 초기화 파일이 자동으로 로드되지 않는 이유는 크론탭이 비로그인, 비인터랙티브 셸 환경에서 실행되기 때문입니다. 따라서 .bashrc나 .bash_profile 같은 초기화 파일을 명시적으로 로드하지 않으면, 스크립트 내에서 정의하지 않은 환경 변수는 인식되지 않습니다.