检查脚本是否由 cron 启动,而不是手动调用

dai*_*isy 32 shell scripting bash cron

cron 在运行程序时是否设置了任何变量?如果脚本是由cron运行的,我想跳过一些部分;否则调用这些部分。

我如何知道 Bash 脚本是否由 cron 启动?

D_B*_*Bye 38

我不知道cron默认情况下会对其环境做任何可以在这里使用的事情,但是您可以做一些事情来获得所需的效果。

1)做一个硬或软链接脚本文件,这样,例如,myscriptmyscript_via_cron指向同一个文件。然后,$0当您想有条件地运行或省略代码的某些部分时,您可以在脚本内部测试 的值。将适当的名称放在您的 crontab 中,您就完成了。

2) 向脚本添加一个选项,并在 crontab 调用中设置该选项。例如,添加一个选项-c,它告诉脚本运行或省略代码的适当部分,并添加-c到您的 crontab 中的命令名称。

当然,cron可以设置任意环境变量,所以你可以RUN_BY_CRON="TRUE"在你的 crontab 中放一行,然后在你的脚本中检查它的值。

  • +1 表示 RUN_BY_CRON=true (11认同)

Tim*_*edy 22

从 cron 运行的脚本不在交互式 shell 中运行。启动脚本也不是。区别在于交互式 shell 具有附加到 tty 的 STDIN 和 STDOUT。

方法一:检查是否$-包含iflag。 i是为交互式 shell 设置的。

case "$-" in
    *i*)
        interactive=1
        ;;
    *)
        not_interactive=1
        ;;
esac
Run Code Online (Sandbox Code Playgroud)

方法二:检查是否$PS1为空。

if [ -z "$PS1" ]; then
    not_interactive=1 
else
    interactive=1
fi
Run Code Online (Sandbox Code Playgroud)

参考:

方法三:测试你的tty。它不是那么可靠,但是对于简单的 cron 作业,您应该没问题,因为 cron 默认情况下不会为脚本分配 tty。

if [ -t 0 ]; then
    interactive=1
else
    non_interactive=1
fi
Run Code Online (Sandbox Code Playgroud)

请记住,您可以使用 强制交互式 shell -i,但如果您这样做,您可能会意识到...

  • 'case "$-" in' 似乎在 bash 脚本中不起作用。 (4认同)

cas*_*cas 9

首先获取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
Run Code Online (Sandbox Code Playgroud)

如果您的脚本是由另一个可能由 cron 启动的进程启动的,那么您可以逐步备份父 PID,直到到达 $CRONPID 或 1(init 的 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
Run Code Online (Sandbox Code Playgroud)

来自 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}"
Run Code Online (Sandbox Code Playgroud)

  • 在 Solaris 上,cron 启动一个 shell,该 shell 运行脚本,该脚本本身会启动另一个 shell。所以脚本中的parent pid并不是cron的pid。 (2认同)

小智 5

如果您的脚本文件被调用cron并且它在第一行包含一个 shell,就像#!/bin/bash您需要为您的目的找到父-父名称一样。

1)cron在给定的时间调用crontab,执行 shell 2) shell 执行您的脚本 3) 您的脚本正在运行

父 PID 在 bash 中作为变量可用$PPIDps获取父PID的父PID的命令是:

PPPID=`ps h -o ppid= $PPID`
Run Code Online (Sandbox Code Playgroud)

但我们需要命令的名称,而不是 pid,所以我们调用

P_COMMAND=`ps h -o %c $PPPID`
Run Code Online (Sandbox Code Playgroud)

现在我们只需要测试“cron”的结果

if [ "$P_COMMAND" == "cron" ]; then
  RUNNING_FROM_CRON=1
fi
Run Code Online (Sandbox Code Playgroud)

现在您可以在脚本中的任何位置进行测试

if [ "$RUNNING_FROM_CRON" == "1" ]; then
  ## do something when running from cron
else
  ## do something when running from shell
fi
Run Code Online (Sandbox Code Playgroud)

祝你好运!