要想整明白后面的开机启动的设置方法,最好不要只知其然而不知其所以然,这里要先从Linux的开机启动顺序开始说起。
下面介绍三种添加开机自启脚本的方法,所测试的系统为 Ubuntu 20.04
Linux系统启动从你的设备接上电源按下开关开始到你登录系统结束,中间有一个复杂但很连贯的过程:
init 系统能够管理和控制 init 进程的行为,并负责组织和运行许多独立的或相关的工作,让系统进入一个用户设定的运行模式中。大多数Linux发行版的 init 系统是 system V 相兼容的,因此被称为 sysvinit,sysvinit 主要依赖于 shell 脚本,但是他一次一个串行的启动进程,决定了它最大的弱点:启动太慢。如果是服务器这类极少进行系统开关操作的话还好,但是如果是个人电脑这样需要经常开关机的话,开机时间太长就难以忍受了。
为了能够更快地启动系统,开发者们对 sysvinit 进行了改进,先后出现了 upstart 和 systemd 这两个主要的新一代 init 系统。目前最新的 Ubuntu 系统就是采用的 systemd 来管理系统,不过仍然兼容 init 系统的启动模式。可以看到 Ubuntu20 的 /sbin/init 是软链接到 /lib/systemd/systemd 上的。systemd 与 init 虽然启动过程不太一样,但最终的目的是一致的,都是要启动那一堆需要开机运行的脚本文件。
在 init 系统模式下,内核调用 init 进程后会首先获取系统运行级别(run-level)的信息,运行级别在这里不是启动优先级,可以理解为运行模式,运行级别共有 0~6 七种:
这几种模式有什么用呢?举个例子,在Ubuntu的终端下,重启指令除了 reboot 外,使用 init 6 也可以实现重启,6 对应的运行级别就是重启,类似地,运行 init 0 指令对应的就是关机。
知道启动级别后就到 /etc/rc.d 文件夹中查找相应的脚本并运行。还会在 /etc/modules-load.d/modules.conf 文件中查找装载到内核的模块。
rc.d 中含有 rc.sysinit、rcN.d(N=0~6,即不同的运行级别对应的运行文件夹,根据运行级别的不同,系统会运行 rc0.d 到 rc6.d 中的相应的脚本程序,来完成相应的初始化工作和启动相应的服务)、rc.local 等文件及或脚本,目前 Ubuntu 已经没有 rc.d 文件夹了,而是把这个文件夹的大多内容直接放在了 /etc 文件夹下了,另外 rc.local 如果需要用到的话还需要自行创建。rc.local 是在所有 init 脚本执行完之后才会运行的脚本,也就是说留给用户用来做一些拓展功能的脚本。
打开 rcN.d 文件夹可以看到里面的文件都是以 S 或者 K 夹数字开头的脚本,S 待表 Start,K代表 Kill ,运行脚本时系统会根据这俩前缀符号来确定传入 start 或者 stop 参数。后面的数字代表执行优先级,也就是运行或者停止的执行优先级。
ubuntu16.04 以后的版本不再使用initd管理系统,因此不再支持 update-rc.d 方式添加开机自启脚本。Ubuntu18 版本开始,使用了systemd 替代了 initd 管理系统,并且默认已经取消了 /etc/rc.local 文件。只能使用 systemctrl 命令进行添加。
systemd 默认读取 /etc/systemd/system下的配置文件,该目录下的文件会链接 (软链接)/lib/systemd/system/ 下的文件。一般系统安装完 /lib/systemd/system/ 下会有 rc-local.service 文件,即我们需要的配置文件。
这里主要记录下如何在 Ubuntu20.04 中通过 /etc/rc.local 文件来设置 shell 脚本的开机启动。
rc-local.service 是系统自带的一个开机自启服务, 但是在 Ubuntu20 的 systemd 启动方式下,该服务默认没有开启。,启用它需要做些简单的配置。
在 路径下 /lib/systemd/system/rc-local.service 的 rc-local.service 的脚本,内容规定了 rc.local 的启动顺序和行为
查看 rc-local.service 文件内容, 前面注释不看了,只看主要内容, 每个字段的解释
[Unit] # 区块:启动顺序与依赖关系
Description=/etc/rc.local Compatibility # 服务的描述,方便人们阅读
Documentation=man:systemd-rc-local-generator(8) # 一组用空格分隔的文档URI列表,这些文档是对此单元的详细说明
ConditionFileIsExecutable=/etc/rc.local # 指定了执行的文件, 表示服务要启动的程序(或脚本)
# 系统会检测指定的路径是否存在并且是一个可执行文件,必须使用绝对路径
After=network.target # 定义启动顺序。示该服务的依赖关系
# Before=xxx.service,代表本服务在xxx.service启动之前启动;
# After=xxx.service,代表本服务在xxx.service之后启动。
[Service] # 区块:启动行为,如何启动,启动类型。
Type=forking # 后台运行的形式
ExecStart=/etc/rc.local start # 指定启动单元的命令或者脚本, 启动服务的命令(命令必须写绝对路径)
TimeoutSec=0
RemainAfterExit=yes # 如果设置这个选择为真,服务会被认为是在激活状态
GuessMainPID=no
#这一段原文件没有,需要自己添加
[Install] # 区块,定义如何安装这个配置文件,即怎样做到开机启动
WantedBy=multi-user.target # WantedBy:表示该服务所在的 Target(服务组)
# multi-user.target 表示多用户命令行状态
Alias=rc-local.service # 指的是表示该服务所属 target
上述命令只写了启动的,重启、停止等可以根据自己情况添加。
注意:启动、重启、停止命令全部要求使用绝对路径
ExecReload 为服务的重启命令
ExecStop 为服务的停止命令
PrivateTmp=True 表示给服务分配独立的临时空间
原始的 rc-local .service 文件的 Unit 段有行代码:
ExecStart=/etc/rc.local start
这行代码规定了这个service在开机启动时所执行的命令是:/etc/rc.local start。即运行 /etc/rc.local 脚本。不过可以看出,这个脚本的内容少了 [Install] 段,也就是说,没有定义如何做到开机启动,所以显然这是这个service是无效的。 因此我们就需要在后面帮他加上 [Install] 段
使用sudo权限修改 rc-local.service, 添加如上面展示的 [Install] 段
sudo vim /lib/systemd/system/rc-local.service
或者 执行 sudo chmod 777 /lib/systemd/system/rc-local.service 赋予修改权限,然后加入以上[Install] 的语句
systemd 默认读取 /etc/systemd/system 下的配置文件, 所以还需要在 /etc/systemd/system 目录下创建软链接,执行下面的命令
$ sudo systemctl enable rc-local.service
Created symlink /etc/systemd/system/multi-user.target.wants/rc-local.service → /lib/systemd/system/rc-local.service.
# 上面的领了等效于一个软链接命令
ln -s /lib/systemd/system/rc-local.service /etc/systemd/system/rc-local.service
这条指令的实际意义是向 /etc/systemd/system 中添加一个 /lib/systemd/system 的软链接(软链接可以理解为快捷方式),看终端中这条指令运行后打印的信息就知道了。
systemd 默认从目录 /etc/systemd/system 读取配置文件。但是,里面存放的大部分文件都是符号链接,指向目录 /lib/systemd/system,真正的配置文件存放在这个目录。systemclt enable 命令用于在上面两个目录之间建立符号链接关系。.service 文件在 Linux 中存在于三个位置:/etc/systemd/system、/run/systemd/system、/lib/systemd/system,这三个目录的配置文件优先级依次从高到低,如果同一选项三个地方都配置了,优先级高的会覆盖优先级低的。
另外:经过实际测试,不使用 systemclt enable 指令创建链接这一步其实也是可以实现开机启动的,这可能跟系统会在上述三种 system 目录下查找 service 并启动有关,只是启动顺序不同而已。
Ubuntu 20.04 默认不存在 /etc/rc.local,需要自己创建 touch /etc/rc.local,rc.local 中主要有两种方法添加开机启动内容
当前文件是 rc.local
#!/bin/bash
# 将你需要执行的命令写在这里,禁止写入死循环命令
echo "开机启动测试" > /home/test.log
exit 0
功能:这里只是简单地实现了向某一个文件里填充数据功能。
1、首先,新建一个 test.sh 脚本, 给test 脚本赋予执行权限 chmod 777 test.sh
当前文件是 test.sh, test.sh 的内容是
#!/bin/bash
time_now=$(date "+%Y-%m-%d %H:%M:%S")
echo "test ok at [$time_now]" > test.log
exit 0
上面 test.sh 脚本的主要作用是获取当前时间,并将其写入 test.log 文件中
2、然后,编辑 /etc/rc.local , 加入test 脚本的调用绝对路径,这里的路径必须是绝对路径
当前文件是 rc.local
#!/bin/sh
cd /PATHtotest
./test.sh & # 最后加上 & 是让脚本启动后在后台运行的作用
exit 0
注意:调用 sh 脚本最后必须加上 & 是让脚本启动后在后台运行的作用, 否则可能会一直卡在开机界面,这个没有去测试过
3、然后执行以下命令赋予 /etc/rc.local 执行权限,这步一定要有,否则没效果的
sudo chmod 777 /etc/rc.local
# 或者
sudo chmod +x /etc/rc.local
使用 sudo systemctl status rc-local.service
查看 rc-local 服务的状态, 显示 loaded 和 enabled。
这一步我没有测试过
Ubuntu 实现shell文件的开机运行(从原理到实现)-pudn.com
Ubuntu 20.04 设置开机自启脚本_小辉_Super的博客-CSDN博客_ubuntu20开机自启动脚本
Linux实现脚本开机自启动 - 白菜没我白 - 博客园
Ubuntu 18 使用 rc.local执行开机启动脚本【转】 - 走看看
Ubuntu 18.04 LTS 配置 rc.local 开机自动启动脚本-老唐笔记
Ubuntu20.04 设置开机自启shell脚本_道阻且长行则将至!的博客-CSDN博客_ubuntu 设置sh自启动
Ubuntu 20.04 开机执行自定义脚本 - 走看看