确定Bash脚本是否从cron

时间:2017-01-23 02:13:01

标签: bash shell cron

我已经实现了一种识别脚本是否从cron作业运行的方法。它使用ps来爬上进程树,并确定是否有任何(递归)父命令包含" cron"或" CRON"。

这个解决方案在工作时很慢(比如大约一秒钟)并且每次调用它时都会影响我拥有的所有脚本。我正在寻找更快的解决方案。

我不想在crontab中为脚本添加任何选项,因为我的目标正是在命令行上没有提供通知选项时定义默认通知行为,并且cron作业的默认行为不同。 / p>

是否有一种相当可靠,快速的方法来确定脚本(或其中一个递归父项)是否是从cron作业启动的?

在我的初始帖子之后,我已经重新编写了代码并且能够对其进行改进,但仍然使用了ps。代码如下,任何建议都是受欢迎的。

is_cron_job()
{
  local PS
  local CMD
  local PID=$$
  while :
  do
    PS="$(ps -h -o ppid,comm -p $PID)"
    [[ "$PS" =~ ^[[:space:]]*([0-9]+)[[:space:]]+(.*)$ ]] || return 1
    PID="${BASH_REMATCH[1]}"
    [[ "$PID" -ge 1 ]] || return 1
    CMD="${BASH_REMATCH[2]}"
    ! [[ "$CMD" =~ crond|CROND ]] || return 0
  done
  return 1
}

3 个答案:

答案 0 :(得分:1)

在运行脚本之前如何在crontab中设置环境变量?

如果在脚本中设置,则意味着它是从cron运行的。

答案 1 :(得分:0)

如果你的操作系统使用的是systemd,你实际上有一种非常可靠的方法可以找出你是否从cron运行。

loginctl show-session $(</proc/self/sessionid) | sed -n '/^Service=/s/.*=//p'

当且仅当该过程由cron启动时,结果为crond

其他方法通常有误报/漏报:

  • 环境变量可以由中间进程操纵(例如,如果crond启动包装脚本,然后启动脚本,则更难保证在crontab中设置的环境变量将被保留)
  • 涉及测试交互式shell或存在tty的方法在管道,启动脚本等条件下会出现误报。
  • 依赖于解析进程树的方法可能会出现误报,因为并非所有名为crond的进程实际上都是 cron守护进程并且可能有错误否定,因为不相关的进程将不再是crond的孩子。

答案 2 :(得分:0)

限制速度因子可能是bash循环,因为bash(就像其他shell一样)被解释并且很慢。以下命令可以避免循环,并且可能更快。

不安全版本

如果存在包含字符串cron的其他进程,则此版本可能会导致误报。我认为你的脚本有同样的问题。

function is_cron_job {
    pstree -s $$ | grep -Fip 'cron'
}

pstree -s $$仅打印当前进程及其祖先(即其名称)。

grep -Fip 'cron'搜索固定(-F),不区分大小写(-i)字符串"cron",如果匹配,则返回0 { {1}}如果没有匹配项(1)。

更安全的版本

我们不是使用-q的进程名称,而是搜索其PID。

cron

需要解决的问题:

  • 以可靠的方式确定function is_cron_job { local cronpid="$(pgrep cron)" if [ $(wc -w <<< "$cronpid") -ne 1 ]; then echo "No or multiple PIDs for cron!" exit 1 fi pstree -sp $$ | grep -Po '\(\d+\)' | grep -Fq "($cronpid)" } 的PID。

  • 以安全的方式从pstree中提取PID 它将非常不常见,但进程可以命名为cron。如果这样的过程是当前过程的祖先,并且something(123)funny123的PID,我们可能会再次产生误报。