스크립트를 수동으로 호출하는 대신 cron으로 시작하는지 확인하세요.

스크립트를 수동으로 호출하는 대신 cron으로 시작하는지 확인하세요.

cron은 프로그램을 실행할 때 변수를 설정합니까? 스크립트가 cron에 의해 실행되는 경우 일부 부분을 건너뛰고 싶습니다. 그렇지 않으면 이러한 부분을 호출하십시오.

Bash 스크립트가 cron에 의해 시작되었는지 어떻게 알 수 있나요?

답변1

여기에서 사용할 수 있는 환경에 대해 기본적으로 어떤 작업을 수행하는지 알지 못하지만 cron원하는 효과를 얻기 위해 수행할 수 있는 몇 가지 작업이 있습니다.

1) 예를 들어 동일한 파일을 가리키 myscript도록 스크립트 파일에 대한 하드 또는 소프트 링크를 만듭니다 . myscript_via_cron그런 다음 $0코드의 특정 부분을 조건부로 실행하거나 생략하려는 경우 스크립트 내부의 값을 테스트할 수 있습니다. crontab에 적절한 이름을 입력하면 완료됩니다.

2) 스크립트에 옵션을 추가하고 crontab 호출에서 옵션을 설정합니다. 예를 들어 -c스크립트가 코드의 적절한 부분을 실행하거나 생략하도록 지시하는 옵션을 추가하고 -ccrontab에 명령 이름을 추가합니다.

물론 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

인용하다:

방법 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$-ii

나는 이것을 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 ]데이터를 스크립트에 연결하면 잘못된 대답이 제공됩니다.

관련 정보