前言:
at命令是Linux的一个专有命令,该命令是旧的计划任务atd服务的客户端命令(at命令是c/s形式的软件套件里的client,客户端),主要的用处就是灵活制定一个工作计划,特定时间自动完成你所设定的任务。
好了,那么可能有老铁会说,这个at命令和crontab好像功能是重叠的,为什么还要了解这个命令呢?
确实,crontab作为老牌计划任务无疑还是功能比较强大的,但,at命令比crontab更为灵活,计划任务的时间范围可能会有一个比较宽泛的设定,能够使用midnight(深夜),noon(中午),teatime(饮茶时间,一般是下午4点)等比较模糊的,但十分口语化的词语来指定时间。因此,会填补crontab的某些应用场景,不过at只能执行一次任务,例如,某些日志需要每天都清理,at是做不到重复的执行的,而crontab是可以执行重复性的周期性的任务的。
下面将就如何使用at命令来做一个可靠的计划任务来进行一个简单的讲解。
一,
at命令存在的形式
at命令是atd服务的客户端,atd服务是一个守护进程。
在centos7这些操作系统上,最小化安装没有at命令的,需要单独安装,安装命令为:
yum install at -y
安装完毕后,需要启动服务,命令为:
systemctl enable atd && systemctl start atd
atd服务的状态
[root@centos61 ~]# systemctl status atd
● atd.service - Job spooling toolsLoaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)Active: active (running) since Sun 2023-05-28 11:29:17 CST; 18min agoMain PID: 666 (atd)Memory: 260.0KCGroup: /system.slice/atd.service└─666 /usr/sbin/atd -fMay 28 11:29:17 centos61 systemd[1]: Started Job spooling tools.
May 28 11:29:17 centos61 systemd[1]: Starting Job spooling tools...
二,
计划任务的三要素
其实,计划任务也是可以按照事件三要素来编写的,也就是时间,地点,事件。那么,具化在Linux系统中,无疑的,时间指的就是任务开始的时间,地点自然是本机了,事件就是任务了。
那么,相对at命令来说,时间的设定是极为丰富的,例如,相对当前时间的10分钟后,today(今天),tomorrow(明天),midnight(深夜),noon(中午),teatime(饮茶时间,一般是下午4点) ,minutes(分钟)、hours(小时)、days(天)、weeks(星期)等比较模糊的 词语来指定时间,用户还能够采用12小时计时制,即在时间后面加上AM(上午)或PM(下午)来说明是上午还是下午。
总的来说,at命令的时间设定更为接近人们的平常的时间概念,也就是说可以十分的口语化。
at命令支持的任务也是比较多的,比如,shell脚本,命令,组合命令等等
at所编排的任务执行完成后都会给自己发送一个本地邮件,例如,以root用户执行了某个任务,那么,任务完成后,root用户将会收到一个邮件,邮件存放位置通常为/var/spool/mail/root
三,
at任务示例
需要说明一下,at命令通常的运行方式是交互模式,也就是先指定时间,然后写要执行的若干条任务,最后退出。
1,
一分钟后,查看/etc/passwd文件的内容
[root@centos61 ~]# date
Sun May 28 13:25:03 CST 2023[root@centos61 ~]# at now +1 minute
at> cat /etc/passwd
at> exit
at> quit
at> <EOT>
job 11 at Sun May 28 13:26:00 2023
等待1分钟后,查看邮件,可以看到任务确实执行了:
Subject: Output from your job 11
To: root@centos61.localdomain
Message-Id: <20230528052600.6CE9620C5D51@centos61.localdomain>
Date: Sun, 28 May 2023 13:26:00 +0800 (CST)
From: root@centos61.localdomain (root)root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:997:User for polkitd:/:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
postgres:x:1000:1000::/home/postgres:/bin/bash
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
2,
三分钟后,在root目录下touch一个名为fuck的文件
[root@centos61 ~]# at now +3 minute
at> touch /root/fuck
at> <EOT>
job 12 at Sun May 28 13:31:00 2023
[root@centos61 ~]# atq
12 Sun May 28 13:31:00 2023 a root
3,
明天的这个时间运行一次df命令,可以看到,该任务标号是14
[root@centos61 ~]# at tomorrow
at> df
at> <EOT>
job 14 at Mon May 29 13:38:00 2023
[root@centos61 ~]# atq
14 Mon May 29 13:38:00 2023 a root
查看14号任务(具体任务在最后面,前面都是环境变量什么的,没什么可看的):
[root@centos61 ~]# at -c 14
#!/bin/sh
# atrun uid=0 gid=0
# mail root 0
umask 22
XDG_SESSION_ID=1; export XDG_SESSION_ID
HOSTNAME=centos61; export HOSTNAME
SELINUX_ROLE_REQUESTED=; export SELINUX_ROLE_REQUESTED
SHELL=/bin/bash; export SHELL
HISTSIZE=1000; export HISTSIZE
SSH_CLIENT=192.168.123.1\ 49853\ 22; export SSH_CLIENT
SELINUX_USE_CURRENT_RANGE=; export SELINUX_USE_CURRENT_RANGE
SSH_TTY=/dev/pts/0; export SSH_TTY
USER=root; export USER
LS_COLORS=rs=0:di=01\;34:ln=01\;36:mh=00:pi=40\;33:so=01\;35:do=01\;35:bd=40\;33\;01:cd=40\;33\;01:or=40\;31\;01:mi=01\;05\;37\;41:su=37\;41:sg=30\;43:ca=30\;41:tw=30\;42:ow=34\;42:st=37\;44:ex=01\;32:\*.tar=01\;31:\*.tgz=01\;31:\*.arc=01\;31:\*.arj=01\;31:\*.taz=01\;31:\*.lha=01\;31:\*.lz4=01\;31:\*.lzh=01\;31:\*.lzma=01\;31:\*.tlz=01\;31:\*.txz=01\;31:\*.tzo=01\;31:\*.t7z=01\;31:\*.zip=01\;31:\*.z=01\;31:\*.Z=01\;31:\*.dz=01\;31:\*.gz=01\;31:\*.lrz=01\;31:\*.lz=01\;31:\*.lzo=01\;31:\*.xz=01\;31:\*.bz2=01\;31:\*.bz=01\;31:\*.tbz=01\;31:\*.tbz2=01\;31:\*.tz=01\;31:\*.deb=01\;31:\*.rpm=01\;31:\*.jar=01\;31:\*.war=01\;31:\*.ear=01\;31:\*.sar=01\;31:\*.rar=01\;31:\*.alz=01\;31:\*.ace=01\;31:\*.zoo=01\;31:\*.cpio=01\;31:\*.7z=01\;31:\*.rz=01\;31:\*.cab=01\;31:\*.jpg=01\;35:\*.jpeg=01\;35:\*.gif=01\;35:\*.bmp=01\;35:\*.pbm=01\;35:\*.pgm=01\;35:\*.ppm=01\;35:\*.tga=01\;35:\*.xbm=01\;35:\*.xpm=01\;35:\*.tif=01\;35:\*.tiff=01\;35:\*.png=01\;35:\*.svg=01\;35:\*.svgz=01\;35:\*.mng=01\;35:\*.pcx=01\;35:\*.mov=01\;35:\*.mpg=01\;35:\*.mpeg=01\;35:\*.m2v=01\;35:\*.mkv=01\;35:\*.webm=01\;35:\*.ogm=01\;35:\*.mp4=01\;35:\*.m4v=01\;35:\*.mp4v=01\;35:\*.vob=01\;35:\*.qt=01\;35:\*.nuv=01\;35:\*.wmv=01\;35:\*.asf=01\;35:\*.rm=01\;35:\*.rmvb=01\;35:\*.flc=01\;35:\*.avi=01\;35:\*.fli=01\;35:\*.flv=01\;35:\*.gl=01\;35:\*.dl=01\;35:\*.xcf=01\;35:\*.xwd=01\;35:\*.yuv=01\;35:\*.cgm=01\;35:\*.emf=01\;35:\*.axv=01\;35:\*.anx=01\;35:\*.ogv=01\;35:\*.ogx=01\;35:\*.aac=01\;36:\*.au=01\;36:\*.flac=01\;36:\*.mid=01\;36:\*.midi=01\;36:\*.mka=01\;36:\*.mp3=01\;36:\*.mpc=01\;36:\*.ogg=01\;36:\*.ra=01\;36:\*.wav=01\;36:\*.axa=01\;36:\*.oga=01\;36:\*.spx=01\;36:\*.xspf=01\;36:; export LS_COLORS
MAIL=/var/spool/mail/root; export MAIL
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/pgsql/bin:/opt/pgsql/data:/root/bin; export PATH
PWD=/root; export PWD
LANG=en_US.UTF-8; export LANG
SELINUX_LEVEL_REQUESTED=; export SELINUX_LEVEL_REQUESTED
PGHOME=/opt/pgsql; export PGHOME
HISTCONTROL=ignoredups; export HISTCONTROL
SHLVL=1; export SHLVL
HOME=/root; export HOME
LOGNAME=root; export LOGNAME
SSH_CONNECTION=192.168.123.1\ 49853\ 192.168.123.61\ 22; export SSH_CONNECTION
PGDATA=/opt/pgsql/data; export PGDATA
LESSOPEN=\|\|/usr/bin/lesspipe.sh\ %s; export LESSOPEN
XDG_RUNTIME_DIR=/run/user/0; export XDG_RUNTIME_DIR
cd /root || {echo 'Execution directory inaccessible' >&2exit 1
}
${SHELL:-/bin/sh} << 'marcinDELIMITER5f46f2f8'
dfmarcinDELIMITER5f46f2f8
4,
指定当天的某个时间执行一次 ls /opt/
[root@centos61 ~]# at 14:51
at> ls /opt
at> <EOT>
job 16 at Sun May 28 14:51:00 2023
5,
指定一个具体时间,执行任务:
很显然,现在是2023 ,2020年是不可接受的时间
[root@centos61 ~]# at 19:19 2020-05-13
at: refusing to create job destined in the past
未来的时间是可以接受的:
[root@centos61 ~]# at 19:19 2023-05-31
at> <EOT>
job 17 at Wed May 31 19:19:00 2023
6,
午夜任务(这里的午夜是指的零点了,今天是星期天,任务的开始时间是星期一7)
[root@centos61 ~]# at midnight
at> ls /opt
at> <EOT>
job 18 at Mon May 29 00:00:00 2023
7,
星期任务(星期三,当前时间执行的任务)
root@centos61 ~]# at Wednesday
at> <EOT>
job 19 at Wed May 31 14:59:00 2023
[root@centos61 ~]# date
Sun May 28 14:59:54 CST 2023
8,
明天下午两点33分的任务:
[root@centos61 ~]# at 02:33PM tomorrow
at> <EOT>
job 20 at Mon May 29 14:33:00 2023
9,
一分钟后执行启动postgresql的脚本:
[root@centos61 ~]# at -f start-pg.sh now +1 minute
job 22 at Sun May 28 16:03:00 2023
查看是否执行了脚本(多说一句,脚本不需要执行权限,因为at命令调用的就是 /bin/sh):
[root@centos61 ~]# ls -l start-pg.sh
-rw-r--r--. 1 root root 52 May 20 17:34 start-pg.sh[root@centos61 ~]# tail /var/spool/mail/root waiting for server to start....2023-05-28 16:03:00.791 CST [21108] LOG: starting PostgreSQL 12.5 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16), 64-bit
2023-05-28 16:03:00.795 CST [21108] LOG: listening on IPv4 address "0.0.0.0", port 35432
2023-05-28 16:03:00.795 CST [21108] LOG: listening on IPv6 address "::", port 35432
2023-05-28 16:03:00.805 CST [21108] LOG: listening on Unix socket "/tmp/.s.PGSQL.35432"
2023-05-28 16:03:00.863 CST [21109] LOG: database system was shut down at 2023-05-28 00:00:17 CST
2023-05-28 16:03:00.890 CST [21108] LOG: database system is ready to accept connectionsdone
server started