cron은 프로그램을 실행할 때 변수를 설정합니까? 스크립트가 cron에 의해 실행되는 경우 일부 부분을 건너뛰고 싶습니다. 그렇지 않으면 이러한 부분을 호출하십시오.
Bash 스크립트가 cron에 의해 시작되었는지 어떻게 알 수 있나요?
답변1
여기에서 사용할 수 있는 환경에 대해 기본적으로 어떤 작업을 수행하는지 알지 못하지만 cron
원하는 효과를 얻기 위해 수행할 수 있는 몇 가지 작업이 있습니다.
1) 예를 들어 동일한 파일을 가리키 myscript
도록 스크립트 파일에 대한 하드 또는 소프트 링크를 만듭니다 . myscript_via_cron
그런 다음 $0
코드의 특정 부분을 조건부로 실행하거나 생략하려는 경우 스크립트 내부의 값을 테스트할 수 있습니다. crontab에 적절한 이름을 입력하면 완료됩니다.
2) 스크립트에 옵션을 추가하고 crontab 호출에서 옵션을 설정합니다. 예를 들어 -c
스크립트가 코드의 적절한 부분을 실행하거나 생략하도록 지시하는 옵션을 추가하고 -c
crontab에 명령 이름을 추가합니다.
물론 cron도 있습니다.할 수 있는임의의 환경 변수를 설정하면 crontab에 한 줄을 추가 RUN_BY_CRON="TRUE"
하고 스크립트에서 해당 값을 확인할 수 있습니다.
답변2
cron에서 실행되는 스크립트는 대화형 셸에서 실행되지 않습니다. 시작 스크립트도 마찬가지입니다. 차이점은 대화형 쉘이 STDIN 및 STDOUT을 tty에 추가한다는 것입니다.
방법 1: 플래그가 $-
포함되어 있는지 확인하세요 i
. i
대화형 쉘에 대해 설정합니다.
case "$-" in
*i*)
interactive=1
;;
*)
not_interactive=1
;;
esac
방법 2: $PS1
비어 있는지 확인하세요.
if [ -z "$PS1" ]; then
not_interactive=1
else
interactive=1
fi
인용하다:
- https://www.gnu.org/software/bash/manual/html_node/Special-Parameters.html
- https://www.gnu.org/software/bash/manual/html_node/Is-this-Shell-Interactive_003f.html
방법 3: tty를 테스트합니다. 그렇지 않다~처럼신뢰할 수 있지만 간단한 cron 작업의 경우 cron은 기본적으로 스크립트에 tty를 할당하지 않으므로 문제가 없습니다.
if [ -t 0 ]; then
interactive=1
else
non_interactive=1
fi
강제 대화형 쉘을 사용할 수 있다는 점을 명심하세요 -i
. 하지만 그렇게 한다면 다음과 같은 사실을 깨닫게 될 것입니다.
답변3
먼저 cron의 PID를 가져온 다음 현재 프로세스의 상위 프로세스 PID(PPID)를 가져와 비교합니다.
CRONPID=$(ps ho %p -C cron)
PPID=$(ps ho %P -p $$)
if [ $CRONPID -eq $PPID ] ; then echo Cron is our parent. ; fi
cron에 의해 시작될 수 있는 다른 프로세스에 의해 스크립트가 시작되면 $CRONPID 또는 1(init의 PID)에 도달할 때까지 상위 PID로 돌아갈 수 있습니다.
아마도 다음과 같을 것입니다(테스트되지 않았지만 작동할 수도 있습니다<TM>).
PPID=$$ # start from current PID
CRON_IS_PARENT=0
CRONPID=$(ps ho %p -C cron)
while [ $CRON_IS_PARENT -ne 1 ] && [ $PPID -ne 1 ] ; do
PPID=$(ps ho %P -p $PPID)
[ $CRONPID -eq $PPID ] && CRON_IS_PARENT=1
done
Deian에서: 이것은 RedHat Linux에서 테스트된 버전입니다.
# start from current PID
MYPID=$$
CRON_IS_PARENT=0
# this might return a list of multiple PIDs
CRONPIDS=$(ps ho %p -C crond)
CPID=$MYPID
while [ $CRON_IS_PARENT -ne 1 ] && [ $CPID -ne 1 ] ; do
CPID_STR=$(ps ho %P -p $CPID)
# the ParentPID came up as a string with leading spaces
# this will convert it to int
CPID=$(($CPID_STR))
# now loop the CRON PIDs and compare them with the CPID
for CRONPID in $CRONPIDS ; do
[ $CRONPID -eq $CPID ] && CRON_IS_PARENT=1
# we could leave earlier but it's okay like that too
done
done
# now do whatever you want with the information
if [ "$CRON_IS_PARENT" == "1" ]; then
CRON_CALL="Y"
else
CRON_CALL="N"
fi
echo "CRON Call: ${CRON_CALL}"
답변4
권위 있는 답변은 없습니다. 여기에 있는 다른 답변 중 일부는 실제로 cron 환경과 일치시키려고 시도하는데 이는 어려운 작업입니다.
CRON='in_cron'
개인적으로 저는 상단과 같이 crontab에 변수를 설정했습니다 . 그런 다음 다음과 같이 테스트할 수 있습니다.
if [ "$CRON" != "in_cron" ]; then
echo "This is not a cron job"
fi
이렇게 하면 Interactive/nohup/ssh와 cron이 확실하게 구분되지만 관련 사용자의 crontab에 변수를 선언해야 합니다. /etc/cron.d 스크립트의 경우 /etc/crontab에 넣을 수 있어야 합니다(적어도 내 Debian 12 시스템에서는 작동합니다).
터미널( $TERM
) 변수는 쉘의 "대화형" 옵션 플래그(특수 매개변수 $-
포함하다 i
). 일부 시스템에서는 설정되어 있지만 TERM=dumb
대부분은 공백으로 두므로 그중 하나를 확인하고 대화형 옵션 플래그를 확인합니다.
if [ "${TERM:-dumb}$-" != "dumb${-#*i}" ]; then
echo "This is not a cron job"
fi
위의 코드는 값이 없을 때 "dumb"라는 단어를 대체합니다 $TERM
. 따라서 변수가 없거나 "dumb"로 설정되거나 $TERM
변수 가 비어 있지 않거나 if가 첫 번째 문자 이전의 모든 문자를 삭제하는 동안 자체와 일치하지 않을 때 조건이 실행됩니다 (no가 없으면 아무것도 삭제되지 않습니다 ).$TERM
$PS1
$-
i
i
나는 이것을 Debian 9, 11 & 12( TERM=
), CentOS 6.4 & 7.4( TERM=dumb
), FreeBSD 7.3 && 11.2( ) TERM=
에서 테스트했습니다 . 이것은 추가로 포함되었지만 $PS1
이제 내 Debian 12 시스템의 cron은 어떻게든 해당 변수를 설정합니다.
적어도 Debian 12에서는 Interactive/nohup과 cron/ssh가 구별됩니다.
단말기 이름도 확인할 수 있습니다. Cron은 일반적으로 (확인하세요!) 터미널을 할당하지 않으므로 다음을 실행할 수 있습니다.tty
그리고POSIX 표준 요구사항(터미널이 없는 경우) not a tty
출력에 다음과 같이 표시되어야 합니다.
if [ "$(tty)" != "not a tty" ]; then
echo "This is not a cron job"
fi
적어도 Debian 12에서는 대화형과 cron/ssh/nohup을 구별합니다.
또 다른 대답매치 상호작용을 언급했습니다 ( : > /dev/tty) 2>/dev/null
.
적어도 Debian 12에서는 이것이 Interactive/nohup을 cron/ssh와 구별합니다.
터미널을 할당하지 않고 cron을 사용하는 네 번째 방법은 표준 입력이 열려 있는지 테스트하는 것입니다. 를 사용하여 이 작업을 수행할 수 있지만 ! [ -t 0 ]
데이터를 스크립트에 연결하면 잘못된 대답이 제공됩니다.