shell 快速确定Bash脚本是否从cron运行的方法

guykilcj  于 2023-10-23  发布在  Shell
关注(0)|答案(3)|浏览(147)

我已经实现了一种方法来识别脚本是否从cron作业运行。它使用ps向上爬进程树,并识别是否有任何(递归)父命令包含“cron”或“CRON”。
这个解决方案在工作时很慢(比如说,大约一秒钟),并且每次调用它们都会影响我的所有脚本。我正在寻找更快的解决方案。
我不想在crontab内的脚本中添加任何选项,因为我的目标是在命令行上没有提供通知选项时定义默认的通知行为,并使该默认行为与cron作业不同。
是否有一种合理可靠、快速的方法来确定脚本(或它的递归父脚本)是否是从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
}
8e2ybdfx

8e2ybdfx1#

在运行脚本之前,在crontab中设置一个环境变量如何?
如果它在脚本中设置,则意味着它是从cron运行的。

hpxqektj

hpxqektj2#

如果你的操作系统使用的是systemd,你实际上有一个非常可靠的方法来确定你是否在从cron运行。

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

当且仅当进程由cron启动时,结果将是crond
其他方法通常具有假阳性/假阴性:

  • 环境变量可以由中间过程(例如,如果crond启动一个 Package 器脚本,然后启动您的脚本,则很难保证crontab中设置的环境变量将被保留)
  • 涉及测试交互式shell或tty存在的方法在管道、启动脚本等情况下会出现误报。
  • 依赖于解析进程树的方法可能会有误报,因为并非所有名为crond的进程实际上 * 都是 * cron守护进程,并且可能会有误报,因为被拒绝的进程将不再是crond的子进程。
xnifntxz

xnifntxz3#

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

不安全版本

如果有其他进程包含字符串cron,此版本可能会导致误报。我觉得你的剧本也有同样的问题。

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

pstree -s $$仅打印当前进程及其祖先(即它们的名称)。
grep -Fip 'cron'搜索固定(-F)、不区分大小写(-i)的字符串"cron",如果匹配则返回0,如果不匹配则返回1-q)。

安全版本

我们不使用cron的进程名,而是搜索它的PID。

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)"
}

待修复问题:

  • 以可靠的方式确定cron的PID。
  • 以安全的方式从pstree中提取PID。

这可能是非常罕见的,但是一个进程可以被命名为something(123)funny。如果这样的进程是当前进程的祖先,并且123cron s PID,则可能再次产生误报。

相关问题