目录
方法有挺多,这里之记录一个。
网上大部分教程都是编辑 /etc/rc.local 文件,然后在该文件内容里追加要运行的 sh 文件的指令即可。这种方法确实挺简单的,但是我在我系统(Ubuntu20.04)下怎么也找不到这个文件在哪,后来在网上查才知道在 Ubuntu18 及之后不再使用 init 管理系统,改用 systemd,也就不再提供 /etc/rc.local 文件的支持了,虽然也有其他办法实现 shell 的开机启动,但总的来说还是通过编辑 /etc/rc.local 文件方便。
init 与 systemd 的区别:
我们知道,在 linux 系统开机的时候,加载完内核后需要启动第一个进程,起初 init 是作为内核启动的第一个进程(位于 sbin/init ,PID为1),init 是串行启动,只有前一个进程启动完,才会启动下一个进程,因此启动过程可能会比较慢。
后来 systemd 优化了这个过程,systemd 就成为了 内核加载的第一个进程(位于/lib/systemd/systemd,PID为1),systemd 尽可能地并行启动进程,减少系统启动等待时间。可以看到在ubuntu20的系统中 sbin/init 其实是通过软链接的方式链接到了 /lib/systemd/systemd 上的。至于软链接是啥?你把他理解为像windows系统中的快捷方式一样的东西就行了。
关于 init 与 systemd 的区别的其他详情还是自行百度查资料吧~
这里主要记录下如何在 Ubuntu20.04 中通过 /etc/rc.local 文件来设置 shell 脚本的开机启动。
在 lib/systemd/system 里面有很多启动脚本,其中有个叫 rc-local.service 的脚本,里面有写到 rc.local 的启动顺序和行为,可以使用 cat /lib/systemd/system/rc-local.service 命令查看这个文件的原始内容如下:
- # SPDX-License-Identifier: LGPL-2.1+
- #
- # This file is part of systemd.
- #
- # systemd is free software; you can redistribute it and/or modify it
- # under the terms of the GNU Lesser General Public License as published by
- # the Free Software Foundation; either version 2.1 of the License, or
- # (at your option) any later version.
-
- # This unit gets pulled automatically into multi-user.target by
- # systemd-rc-local-generator if /etc/rc.local is executable.
- [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
不过,一般正常的启动文件要分为三部分:
- [Unit] 段: 启动顺序与依赖关系
- [Service] 段: 启动行为,如何启动,启动类型
- [Install] 段: 定义如何安装这个配置文件,即怎样做到开机启动
里面叽里瓜啦写了一堆我也看不懂具体的意思,但是一点可以确认的是他负责 /etc/rc.local 的启动,而 /etc/rc.local 正是前面说的那个配置开机启动脚本的文件。不过可以明显看出,这个脚本的内容少了 [Install] 段,也就是说,没有定义如何做到开机启动,所以显然这样配置是无效的。 因此我们就需要在后面帮他加上 [Install] 段,首先执行 sudo chmod 777 /lib/systemd/system/rc-local.service 赋予修改权限,然后加入以下语句,然后保存退出。
- [Install]
- WantedBy=multi-user.target # WantedBy:表示该服务所在的 Target(服务组)
下一步是在 /etc 中创建 rc.local 脚本,然后可以把你要开机启动的内容写入到这个脚本中即可。
举个例子;
我现在在桌面新建一个 test 文件夹,在该文件夹内创建一个名为 hhh.sh 的 shell 脚本文件,内容如下:
- #!/bin/sh
- time_now=$(date "+%Y-%m-%d %H:%M:%S")
- echo "test ok at [$time_now]" > a.log
- exit 0
作用是获取当前时间,并将其写入 a.log 文件中,我们可以运行以下这个sh文件看看效果:
可以看到,执行完这个脚本之后在 test 文件夹下多出一个 a.log 的文件,里面就是我们要打印的内容。接下来,删除这个 a.log 文件,编辑前面在 /etc 文件夹下创建的 rc.local 脚本(sudo gedit rc.local):
- #!/bin/sh
- cd /home/wsx/Desktop/test
- chmod 777 hhh.sh
- ./hhh.sh & # 最后加上 & 是让脚本启动后在后台运行的作用
- exit 0
然后执行以下命令赋予 rc.local 执行权限,这步一定要有,否则没效果的
sudo chmod 777 etc/rc.local
实测下面这一步不需要。。。执行了也没啥影响
(然后由于 systemd 默认读取 /etc/systemd/system 下的配置文件,因此我们还要在 /etc/systemd/system/ 下创建 /lib/systemd/system/rc.local.service 的软链接:)
sudo ln -s /lib/systemd/system/rc-local.service /etc/systemd/system/
然后重启 ubuntu,再在 test 文件夹下查看是否生成了 a.log 文件。
成功生成 a.log 文件并打印正确信息,启动完成~
总之,在确定你要开机启动哪个 shell 文件的前提下,只需两个步骤:
(1)在 /etc/systemd/system/rc-local.service 脚本中添加一个 Install 段
(2)在 /etc 目录下新建 rc.local 脚本,写入开机启动的 shell 命令,并使用 chmod 赋予其执行权限