Home 计划任务 cron 和 at
Post
Cancel

计划任务 cron 和 at

atcron可以用于在指定的时间或日期运行命令和脚本,二者的主要区别是 at命令用于仅运行一次的任务,而cron 用于定期地运行作业,cron的频率通常设置为每天、每周或每月,也可以每年,由用户控制运行的频率和时间。二者都需要有 适当的权限是执行任务。二者一般共存。

安装和参考手册

1
2
3
$ sudo apt install at cron
$ man 1 at
$ man 8 cron

at

at程序安装完后,会有一个守护进程atd,应该是由它执行定时任务的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ sudo apt install at
$ sudo systemctl status atd
● atd.service - Deferred execution scheduler
     Loaded: loaded (/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2023-02-14 17:29:04 CST; 7min ago
       Docs: man:atd(8)
    Process: 1288 ExecStartPre=/usr/bin/find /var/spool/cron/atjobs -type f -name =* -not -newercc /run/systemd -delete (code=exited, status=0/>
   Main PID: 1330 (atd)
      Tasks: 1 (limit: 308970)
     Memory: 644.0K
     CGroup: /system.slice/atd.service
             └─1330 /usr/sbin/atd -f

2月 14 17:29:04 debian systemd[1]: Starting Deferred execution scheduler...
2月 14 17:29:04 debian systemd[1]: Started Deferred execution scheduler.

需要注意的:
(1)因为平时程序的运行都是在/bin/bash 这种shell中执行的,这个shell里面是有很多环境变量的,命令行敲的 程序很可能使用了部分shell的环境变量。而在at中,是没有设置环境变量的,如果用到了环境环境(尤其是脚本程序),需要先设置, 可以在脚本中设置好,然后调用可执行程序。

(2)bash一般都是有tty的,后台的atd则没有,所以标准输出,标准错误估计会丢失,需要使用syslog记录到日志中。 或者重定向到日志文件中。

at指定的时间表达式

at因为是在指定时间timespec,执行设置的程序或脚本,这个时间的格式是 at 规定的。 可以参考man 1 at/usr/share/doc/at/timespec,好像只能到分,不能精确到秒?

(1)HH:MM 格式,指定小时和分钟,24小时制。如10:01,14:02,19:25这种。另外,也可以使用12小时制的,后面带上 AM/PM 即可。如 02:02 PM 就等效于 14:02。另外还有几个特定的alias,midnight,noon,teatime,分别代表 00:00,12:00,16:00

(2)now + count time-units 格式,相对当前时间,时间单位有 minutes, hours, days, weeks ,如 now +1 hours 即1小时后, now +3 days 即3天后。now是相对现在,具体还有其他,一般now比较常见,具体的格式也较多,如 at 4pm + 3 days , at 1am tomorrow 这种都是可以的,都是设置的方式,看的明白即可。详细的时间格式在文档中,了解常用方式即可。

(3)MMDD[CC]YY, MM/DD/[CC]YY, DD.MM.[CC]YY, [CC]YY-MM-DD,The specification of a date must follow the specification of the time of day. 可以在时间后面加上日期进行补充,日期是英文中的表达方式,月日年 MMDD[CC]YY, MM/DD/[CC]YY, DD.MM.[CC]YY,而年月日只有 [CC]YY-MM-DD[CC]YY表示完整年,YY是简写年,如2022年,CC就是20,YY就是22。如果指定的时间已经过时了,则at会立即执行。

(4)其他格式,比如还可以使用月份 at 10am Jul 31 等。

(5)使用 -t 参数,-t time run the job at time, given in the format [[CC]YY]MMDDhhmm[.ss],测试,秒不起作用

前台交互式at命令

at 后跟一个timespec,然后输入命令,最后输入EOF结束。 如果时间格式不对,at会直接报错,Garbled time

1
2
3
4
5
6
$ at 10:45 02152023
warning: commands will be executed using /bin/sh
at> echo "my test date and time" >> ~/qwer.txt
at> date >> ~/qwer.txt
at> <EOT>
job 10 at Wed Feb 15 10:45:00 2023

也可以使用管道

1
$ echo "date >> ~/at-test.txt" | at now +2 minute

使用 -t 参数设置的时间格式

1
2
3
4
5
$ at -t 202302151103.12
warning: commands will be executed using /bin/sh
at> date >> ~/qwer.txt
at> <EOT>
job 12 at Wed Feb 15 11:03:00 2023

at配置的命令最终是写在文件中的,如/var/spool/cron/atjobs,所以重启后仍存在

查看at作业

使用 at -latq joy为当前用户名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ which atq | xargs file
/usr/bin/atq: symbolic link to at

$ at -l
6	Wed Feb 15 13:00:00 2023 a joy
4	Wed Feb 15 18:01:00 2023 a joy
5	Wed Feb 15 13:02:00 2023 a joy
9	Sat Feb 18 16:00:00 2023 a joy

$ atq
6	Wed Feb 15 13:00:00 2023 a joy
4	Wed Feb 15 18:01:00 2023 a joy
5	Wed Feb 15 13:02:00 2023 a joy
9	Sat Feb 18 16:00:00 2023 a joy

第一列是job号。

查看具体job的执行命令

使用at -l后列出了所有的jobs,查看具体某个job使用 -c 参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
joy@debian:~$ at -c 9
#!/bin/sh
# atrun uid=1001 gid=1001
# mail joy 0
umask 2
WK=/data/joy_workdir; export WK
LC_ADDRESS=zh_CN.UTF-8; export LC_ADDRESS
LC_NAME=zh_CN.UTF-8; export LC_NAME
LC_MONETARY=zh_CN.UTF-8; export LC_MONETARY
PWD=/home/joy; export PWD
LOGNAME=joy; export LOGNAME
XDG_SESSION_TYPE=tty; export XDG_SESSION_TYPE
MOTD_SHOWN=pam; export MOTD_SHOWN
HOME=/home/joy; export HOME
LC_PAPER=zh_CN.UTF-8; export LC_PAPER
LANG=en_US.UTF-8; export LANG

...省略一些环境变量

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin; export PATH
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1001/bus; export DBUS_SESSION_BUS_ADDRESS
SSH_TTY=/dev/pts/6; export SSH_TTY
LC_NUMERIC=zh_CN.UTF-8; export LC_NUMERIC
cd /home/joy || {
	 echo 'Execution directory inaccessible' >&2
	 exit 1
}
echo "test" >> /home/joy/qwer.txt

可以看出at是会为命令先设置一些环境变量的,可以检查一下。

删除job

使用 at -rat -datrm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
joy@debian:~$ at -l
6	Wed Feb 15 13:00:00 2023 a joy
4	Wed Feb 15 18:01:00 2023 a joy
5	Wed Feb 15 13:02:00 2023 a joy
9	Sat Feb 18 16:00:00 2023 a joy

joy@debian:~$ which atrm | xargs file
/usr/bin/atrm: symbolic link to at

joy@debian:~$ at -r 5

joy@debian:~$ at -l
6	Wed Feb 15 13:00:00 2023 a joy
4	Wed Feb 15 18:01:00 2023 a joy
9	Sat Feb 18 16:00:00 2023 a joy

at 用户权限

at.allow, at.deny - determine who can submit jobs via at or batch

The /etc/at.allow and /etc/at.deny files determine which user can submit commands for later execution via at(1) or batch(1). The format of the files is a list of usernames, one on each line. Whitespace is not permitted. If the file /etc/at.allow exists, only usernames mentioned in it are allowed to use at. If /etc/at.allow does not exist, /etc/at.deny is checked, every username not mentioned in it is then allowed to use at. An empty /etc/at.deny means that every user may use at. If neither exists, only the superuser is allowed to use at.

是对哪些用户可以使用at的一个限制,不过root用户会忽略掉这里的限制。

at小结

at 常用命令参数

optfunction
-mSend mail to the user when the job has completed even if there was no output.
-MNever send mail to the user.
-f fileReads the job from file rather than standard input.
-t timerun the job at time, given in the format [[CC]YY]MMDDhhmm[.ss]
-lIs an alias for atq.
-rIs an alias for atrm.
-dIs an alias for atrm.
-ccats the jobs listed on the command line to standard output.

at 相比 cron ,特点是只运行一次,使用更简单一些。

batch命令

at命令还有可附带的命令batch,该命令功能和at基本一样, 唯一的区别是使用该命令设置的任务只会在系统空闲时执行。另外使用该命令设置的任务默认队列名称为b 。


cron

cron 可以用来循环执行定时任务。还有一个辅助扩展工具 anacron

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
joy@debian:~$ sudo apt install cron anacron

joy@debian:~$ sudo systemctl status cron.service 
● cron.service - Regular background program processing daemon
     Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2023-02-14 17:51:12 CST; 17h ago
       Docs: man:cron(8)
   Main PID: 1291 (cron)
      Tasks: 1 (limit: 308970)
     Memory: 484.0K
     CGroup: /system.slice/cron.service
             └─1291 /usr/sbin/cron -f

2月 15 10:17:01 debian CRON[2045733]: pam_unix(cron:session): session closed for user root
2月 15 10:30:01 debian CRON[2047061]: pam_unix(cron:session): session opened for user root by (uid=0)
2月 15 10:30:01 debian CRON[2047062]: (root) CMD ([ -x /etc/init.d/anacron ] && if [ ! -d /run/systemd/system ]; then /usr/sbin/invoke-rc.d anacro>
2月 15 10:30:01 debian CRON[2047061]: pam_unix(cron:session): session closed for user root
2月 15 11:17:01 debian CRON[2051858]: pam_unix(cron:session): session opened for user root by (uid=0)
2月 15 11:17:01 debian CRON[2051859]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
2月 15 11:17:01 debian CRON[2051858]: pam_unix(cron:session): session closed for user root
2月 15 11:30:01 debian CRON[2053143]: pam_unix(cron:session): session opened for user root by (uid=0)
2月 15 11:30:01 debian CRON[2053144]: (root) CMD ([ -x /etc/init.d/anacron ] && if [ ! -d /run/systemd/system ]; then /usr/sbin/invoke-rc.d anacro>
2月 15 11:30:01 debian CRON[2053143]: pam_unix(cron:session): session closed for user root

crontab配置工具

cron是依据配置文件的,那些周期任务被写到了文件中,配置工具就是 crontab工具,使用它来进行配置,而不是直接修改配置文件。 在Debian系统上,cron的相关配置文件,(CentOs的可能不同)

1
2
3
4
$ ls /etc/cron
cron.d/       cron.daily/   cron.hourly/  cron.monthly/ crontab       cron.weekly/

# 以及 /var/spool/cron/crontabs

crontabcron 的真正配置工具,可以参考手册 man 1 crontab。每个用户配置的crontab是独立的, /etc/cron.allow/etc/cron.deny 类似at工具的,可以配置用户是否允许使用cron。root用户则无视这两个权限文件。

crontab配置表达式

我们用crontab -e进入当前用户的工作表编辑,可以选择nano 或 vim 编辑器,每一行是一条命令。具体配置格式参考 man 5 crontab

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ crontab -e

# (nano 编辑器中)
# Edit this file to introduce tasks to be run by cron.
# 
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
# 
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').
# 
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
# 
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
# 
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
# 
# For more information see the manual pages of crontab(5) and cron(8)
# 
# m h  dom mon dow   command

每行命令有6个域,构成为 循环时间+动作,前面的5个用来设置循环周期,最后一个域设置执行的命令。 另外,可以在前面先填写一些环境变量,不过应该会被所有命令共享,不如写在命令脚本中。

时间域

1
<minute>  <hour>  <day-of-month>  <month>  <day-of-week>  <command>
范围描述
min0-59表示每个小时中的第xx分钟都要执行后面的命令
hour0-23表示每天的第xx小时要执行命令
day-of=month1-31表示每月的第xx天要执行命令
month1-12表示每年的第xx月要执行命令
day-of-week0-7表示每周的第xx天要执行命令,0和7都代表sunday

如果全部设置,那么只能每年执行一次了,所以在范文中也有一些特殊的操作符可以填写。

特殊字符功能
*表示匹配该域的任意值。假如在hour域使用*, 即表示每小时都要执行命令,这个最常用
,表示枚举值,类似数组中的逗号用法 ,如在min域中写 “15,30,45”,就表示在每15和30和45分钟执行命令
-表示范围,如在day-of-month域写 “1-15”,表示每个月的第1天到第15天都执行
/表示从起始时间A开始,每间隔B时间执行一次,如在min域写 “3/20”,表示第3分钟执行一次,后面23,43分钟也执行,一般前面的起始时间会写一个 * 号,如 “*/20” 这样用,就表示每20分钟执行一次
其他还有一些其他的特殊用法,如 ?,L,W,# 等,不常用

有一些alias可以替代前面的5个时间域: | string | meaning | | —— | —————————— | | @reboot | Run once, at startup. | | @yearly | Run once a year, “0 0 1 1 *”. | | @annually | (same as @yearly) | | @monthly | Run once a month, “0 0 1 * *”. | | @weekly | Run once a week, “0 0 * * 0”. | | @daily | Run once a day, “0 0 * * *”. | | @midnight | (same as @daily) | | @hourly | Run once an hour, “0 * * * *”. |

命令域

命令域中最好写一个脚本,可以设置一些自己需要的环境变量。

example

每2分钟记录一次时间,使用 crontab -e 进入编写

1
*/2 * * * *  /usr/bin/date >> /home/joy/test.txt

编写完后不需要额外执行其他动作,即可生效,

1
2
3
4
5
6
7
# wait some time
$ cat ~/test.txt 
2023年 02月 15日 星期三 15:14:01 CST
2023年 02月 15日 星期三 15:16:01 CST
2023年 02月 15日 星期三 15:18:01 CST
2023年 02月 15日 星期三 15:20:01 CST
2023年 02月 15日 星期三 15:22:01 CST

删除周期任务

直接crontab -e ,删除相关行即可。 清空当前用户的 crontab ,可以执行 crontab -r

cron 小结

cron的任务管理是通过直接操作文本的,通过crontab -e 进入编辑即可,编辑完自动生效,环境变量用户自己管理。

其他的几个主要选项。

optmeaning
-e编辑某个用户的 crontab 文件内容。如果不指定用户,则表示编辑当前用户的 crontab 文件。
-l显示某用户的 crontab 文件内容,如果不指定用户,则表示显示当前用户的 crontab 文件内容。
-r从 /var/spool/cron 删除某用户的 crontab 文件,如果不指定用户,则默认删除当前用户的 crontab 文件。

anacron

anacron 工具是一个cron工具的辅助工具,有一些扩展功能, 如cron 如果关机了,导致错过执行了一些命令,下次就不会执行了,配置anacron则可以让其执行; anacron还可以立即执行相关的任务命令,而cron不行。

二者的关系:anacron 与 cron 协同工作,因此严格来说前者不是后者的替代品,而是一种调度任务的有效可选方案。 许多系统管理员配置了一个 cron 作业来在深夜备份远程工作者计算机上的数据,结果却发现该作业在过去六个月中只运行过一次。 anacron 确保重要的工作在 可执行的时候 发生,而不是必须在安排好的 特定时间点 发生。

anacron使用自己的配置文件帮助cron实现扩展。

1
2
3
4
5
6
7
8
/etc/anacrontab
       Contains specifications of jobs.  See anacrontab(5) for a complete description.
/var/spool/anacron
       This directory is used by Anacron for storing timestamp files.
/lib/systemd/system/anacron.service
       This file provides systemd service for anacron.
/lib/systemd/system/anacron.timer
        This file provides systemd timer for anacron. Currently the service is triggered hourly through systemd timer.

anacron 会以 1 天、1周(7天)、一个月作为检测周期,判断是否有定时任务在关机之后没有执行。如果有这样的任务,那么 anacron 会在特定的时间重新执行这些定时任务。 anacron 读取的时间记录文件。anacron 会分析现在的时间与时间记录文件所记载的上次执行 anacron 的时间,将两者进行比较, 如果两个时间的差值超过 anacron 的指定时间差值(一般是 1 天、7 天和一个月),就说明有定时任务没有执行, 这时 anacron 会介入并执行这个漏掉的定时任务,从而保证在关机时没有执行的定时任务不会被漏掉。

anacron 的配置

anacron 依赖 /etc/anacrontab 中的配置去检测cron是否有漏掉执行的任务。 该文件一般有root用户编辑,具体的格式参考 man 5 anacrontab

anacron安装后,有一个默认的 /etc/anacrontab ,里面有一些配置,符合日常使用场景需要了,不深入研究了。

This post is licensed under CC BY 4.0 by the author.