cron이 수동으로 호출하지 않고 스크립트를 시작했는지 확인


23

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

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


왜 우리 만하지 ps?
terdon


@terdon : 아마도 ps상당히 잘못 문서화되어 있기 때문에 (특히 여러 가지 구문 스타일을 지원하는 Linux 버전) 매뉴얼 페이지는 대부분의 도구보다 훨씬 밀도가 높고 암호가 적습니다. 나는 대부분의 사람들이 도구 ps가 얼마나 유용하고 다재다능한지를 깨닫지 못한다고 생각 합니다.
cas

답변:


31

나는 cron그것이 환경에서 기본적으로 여기에서 사용할 수있는 일을 알고 있지만, 원하는 효과를 얻기 위해 할 수있는 몇 가지가 있습니다.

1) 하드 또는 소프트 있도록 스크립트 파일에 대한 링크, 예를 들어, 확인 myscriptmyscript_via_cron같은 파일을 가리키고. 그런 다음 $0코드의 특정 부분을 조건부로 실행하거나 생략 할 때 스크립트 내부 의 값을 테스트 할 수 있습니다 . crontab에 적절한 이름을 입력하면 설정됩니다.

2) 스크립트에 옵션을 추가하고 crontab 호출에서 해당 옵션을 설정하십시오. 예를 들어, -c스크립트가 코드의 해당 부분을 실행 또는 생략하도록 지시하고 -ccrontab의 명령 이름에 추가 하도록 옵션을 추가 하십시오.

물론 cron 임의의 환경 변수를 설정할 있으므로 RUN_BY_CRON="TRUE"crontab 과 같은 줄을 넣고 스크립트에서 그 값을 확인할 수 있습니다.


7
RUN_BY_CRON = true 인 경우 +1
cas

cas의 답변은 매우 잘 작동하며 다른 용도로도 사용될 수 있습니다.
Deian

19

cron에서 실행되는 스크립트는 대화식 쉘에서 실행되지 않습니다. 시작 스크립트도 아닙니다. 차이점은 대화식 쉘에는 tty에 STDIN 및 STDOUT이 첨부되어 있다는 것입니다.

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

참조 : http://techdoc.kvindesland.no/linux/gnubooks/bash/bashref_54.html

방법 3 : tty를 테스트하십시오. 아니에요 으로 신뢰할 수있는,하지만 크론 스크립트에 청각 장애를 할당 기본적으로하지 않는 간단한 cron 작업에 대한 당신은 확인해야합니다.

if [ -t 0 ]; then
    interactive=1
else
    non_interactive=1
fi

그러나를 사용하여 대화식 쉘을 강제 실행할 수는 있지만 -i이 작업을 수행하고 있는지 알고있을 것입니다.


1
systemd에서 스크립트를 시작했는지 여부를 확인할 때 $ PS1 명령이 작동하지 않습니다. $
-one

1
위니펙 대학교 링크가 깨졌습니다.
WinEunuuchs2Unix

1
@TimKennedy 천만에요 .... from Edmonton :)
WinEunuuchs2Unix

bash 스크립트에서 'case "$-"in'이 작동하지 않는 것 같습니다.
Hobadee

@Hobadee - 모든 bash내가 가지고 $에 액세스 할 수 - 등을 수행 dash하고 ksh. Solaris의 제한된 쉘조차도 가지고 있습니다. 작동하지 않는 곳에서 어떤 플랫폼을 사용하려고합니까? 무엇을 case "$-" in *i*) echo true ;; *) echo false ;; esac보여줍니까?
팀 케네디

7

먼저 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 (초기 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}"

1
Solaris에서 cron은 쉘을 시작하고 쉘은 다른 쉘을 시작하는 스크립트를 실행합니다. 따라서 스크립트의 부모 pid는 cron의 pid가 아닙니다.

4

스크립트 파일이 호출되고 cron첫 번째 행에 쉘이 포함되어 #!/bin/bash있으면 목적에 따라 부모-부모 이름을 찾아야합니다.

1) cron주어진 시간에 호출되어 crontab쉘을 실행합니다. 2) 쉘이 스크립트를 실행합니다. 3) 스크립트가 실행 중입니다.

부모 PID는 bash에서 variable로 사용할 수 있습니다 $PPID. ps명령은 PID가 부모의 부모의 PID를 얻을 수 있습니다 :

PPPID=`ps h -o ppid= $PPID`

그러나 우리는 pid가 아닌 명령의 이름이 필요합니다.

P_COMMAND=`ps h -o %c $PPPID`

이제 "cron"에 대한 결과 만 테스트하면됩니다.

if [ "$P_COMMAND" == "cron" ]; then
  RUNNING_FROM_CRON=1
fi

이제 스크립트의 어느 곳에서나 테스트 할 수 있습니다

if [ "$RUNNING_FROM_CRON" == "1" ]; then
  ## do something when running from cron
else
  ## do something when running from shell
fi

행운을 빕니다!


이것은 Linux ps에서만 작동합니다. MacOS (Linux 및 * BSD도 가능)의 경우 다음 P_COMMAND를 사용할 수 있습니다.P_COMMAND=$(basename -a $(ps h -o comm $PPPID))
mdd

1

FreeBSD 또는 Linux에서 작동합니다 :

if [ "Z$(ps o comm="" -p $(ps o ppid="" -p $$))" == "Zcron" -o \
     "Z$(ps o comm="" -p $(ps o ppid="" -p $(ps o ppid="" -p $$)))" == "Zcron" ]
then
    echo "Called from cron"
else
    echo "Not called from cron"
fi

원하는만큼 프로세스 트리를 올라갈 수 있습니다.


1

"내 출력이 터미널입니까 아니면 스크립트에서 실행되고 있습니까?"라는 질문에 대한 일반적인 해결책은 다음과 같습니다.

( : > /dev/tty) && dev_tty_good=y || dev_tty_good=n

0

echo $TERM | mail me@domain.comcron 의 간단한 것은 Linux와 AIX 모두에서 cron이$TERM 이 'dumb' 되어있는 .

이제 이론적으로 여전히 실제 바보 같은 터미널이있을 수 있지만 대부분의 경우 충분하다고 생각합니다 ...


0

권위있는 대답은 없지만 프롬프트 ( $PS1) 및 터미널 ( $TERM) 변수는 여기에 꽤 괜찮습니다. 일부 시스템 TERM=dumb은 대부분 비워두고 설정 하므로 다음 중 하나만 확인하십시오.

if [ "${TERM:-dumb}$PS1" != "dumb" ]; then
  echo "This is not a cron job"
fi

위의 코드는에 대한 값이 없을 때 "dumb"라는 단어를 대체합니다 $TERM. 따라서,이 아니오 조건부 화재 $TERM또는 $TERM"바보"나 경우 설정$PS1 변수가 비어 있지 않습니다.

나는 이것을 Debian 9 ( TERM=), CentOS 6.4 & 7.4 ( TERM=dumb) 및 FreeBSD 7.3 ( TERM=) 에서 테스트했습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.