多个脚本需要启动?可以分别建service管理
在实际的Linux系统运维或嵌入式开发中,经常会遇到这样的需求:多个自定义脚本需要在系统开机时自动运行。比如一个用于启动摄像头服务,一个用于初始化传感器,另一个用于同步时间或上传数据。如果只是简单地把它们写进/etc/rc.local或者用crontab的@reboot,不仅难以管理,还容易出错。
更好的做法是——为每个脚本单独创建一个 systemd 服务(service)。这样不仅能实现精准控制(启动、停止、重启、查看状态),还能自动处理依赖关系、崩溃后自动重启,并且符合现代 Linux 系统的标准规范。
本文将手把手教你如何为多个启动脚本创建独立的 systemd 服务,确保系统稳定、可维护性强,适合用于生产环境或复杂项目部署。
1. 为什么推荐使用 systemd 而不是 rc.local?
你可能听说过/etc/rc.local是传统的开机执行方式,但在当前主流发行版(如 Ubuntu 20.04+、Debian 11+、CentOS 8+)中,rc.local已被弱化甚至默认不启用。
相比之下,systemd具有以下优势:
- 支持按依赖顺序启动(例如:等网络就绪后再运行脚本)
- 可以指定运行用户和权限,更安全
- 支持失败自动重启(
Restart=on-failure) - 提供日志追踪(通过
journalctl查看输出) - 支持启用/禁用服务,灵活管理
一句话总结:用 systemd 建 service,才是现代 Linux 下管理开机脚本的“正确姿势”。
2. 创建第一个 systemd 服务
假设我们有一个名为start-camera.sh的脚本,路径为/home/pi/start-camera.sh,希望它在开机时自动运行。
### 2.1 编写脚本并赋予执行权限
首先确认脚本存在且可执行:
#!/bin/bash # /home/pi/start-camera.sh echo "Starting camera service..." >> /var/log/camera.log sleep 2 mjpg_streamer -i "input_raspicam.so" -o "output_http.so port=8080"然后添加执行权限:
sudo chmod +x /home/pi/start-camera.sh注意:建议所有脚本使用绝对路径调用命令(如
/usr/bin/mjpg_streamer),避免因环境变量缺失导致失败。
### 2.2 创建 service 文件
使用文本编辑器创建一个.service文件:
sudo nano /etc/systemd/system/camera.service输入以下内容:
[Unit] Description=Camera Streaming Service After=network.target ConditionFileIsExecutable=/home/pi/start-camera.sh [Service] WorkingDirectory=/home/pi ExecStart=/bin/bash /home/pi/start-camera.sh StandardOutput=inherit StandardError=inherit Restart=on-failure RestartSec=5 User=pi Group=pi [Install] WantedBy=multi-user.target参数说明:
Description:服务描述,便于识别After=network.target:表示在网络服务启动之后再运行此脚本ConditionFileIsExecutable:检查脚本是否可执行,防止误启ExecStart:实际要运行的命令Restart=on-failure:失败时自动重启,增强稳定性User/Group:以普通用户身份运行,提升安全性WantedBy=multi-user.target:表示在多用户模式下启用
保存退出(Ctrl+O,Enter,Ctrl+X)。
3. 启用并测试服务
完成 service 文件创建后,需要通知 systemd 加载新配置。
### 3.1 重新加载 systemd 配置
sudo systemctl daemon-reload这一步非常重要,否则系统不会发现新的服务。
### 3.2 设置开机自启
sudo systemctl enable camera.service你会看到提示:Created symlink /etc/systemd/system/multi-user.target.wants/camera.service → /etc/systemd/system/camera.service
说明已成功加入开机启动队列。
### 3.3 手动启动并查看状态
现在可以立即启动服务进行测试:
sudo systemctl start camera.service查看运行状态:
sudo systemctl status camera.service正常输出应包含:
● camera.service - Camera Streaming Service Loaded: loaded (/etc/systemd/system/camera.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2025-04-05 10:00:00 CST; 5s ago Main PID: 1234 (bash) Tasks: 3 (limit: 4915) CGroup: /system.slice/camera.service ├─1234 /bin/bash /home/pi/start-camera.sh └─1235 mjpg_streamer -i input_raspicam.so -o output_http.so port=8080如果显示active (running),说明服务已成功运行!
4. 管理多个脚本?那就建多个 service!
如果有多个脚本需要分别管理,比如:
| 脚本名称 | 功能 |
|---|---|
start-camera.sh | 启动视频流 |
sensor-init.sh | 初始化温湿度传感器 |
sync-time.sh | 校准系统时间 |
upload-data.sh | 每分钟上传一次数据 |
最佳实践是:每个脚本对应一个独立的 service 文件!
例如,为传感器初始化脚本创建服务:
sudo nano /etc/systemd/system/sensor-init.service内容如下:
[Unit] Description=Sensor Initialization Script After=multi-user.target [Service] Type=oneshot ExecStart=/bin/bash /home/pi/sensor-init.sh RemainAfterExit=yes User=pi [Install] WantedBy=multi-user.target注意这里用了Type=oneshot和RemainAfterExit=yes,适用于只运行一次的初始化任务。
同样操作,为定时上传脚本创建服务(配合内部循环或 cron):
[Unit] Description=Data Upload Daemon After=network.target [Service] ExecStart=/bin/bash /home/pi/upload-data.sh Restart=always User=pi [Install] WantedBy=multi-user.target然后依次执行:
sudo systemctl daemon-reload sudo systemctl enable sensor-init.service sudo systemctl enable upload-data.service这样一来,四个脚本各自独立、互不影响,还可以单独控制:
sudo systemctl stop camera.service sudo systemctl disable sensor-init.service sudo systemctl restart upload-data.service5. 常见问题与调试技巧
即使配置正确,有时服务也无法正常运行。以下是常见问题及解决方法。
### 5.1 脚本没输出?用 journalctl 查日志
不要再去翻.log文件了,直接使用:
sudo journalctl -u camera.service -f-u:指定服务名-f:实时跟踪日志输出(类似tail -f)
这是最强大的调试工具,能捕获 stdout/stderr 输出。
### 5.2 权限错误?检查用户和文件路径
常见错误包括:
- 脚本没有执行权限 → 用
chmod +x - 使用 root 写的日志文件,普通用户无法写入 → 修改目录权限或改用
/tmp - 调用了 GUI 程序但无 DISPLAY 环境变量 → 需设置
Environment=DISPLAY=:0
可在 service 中添加环境变量:
[Service] Environment=DISPLAY=:0 Environment=XAUTHORITY=/home/pi/.Xauthority### 5.3 服务启动太快,依赖资源未准备好?
比如脚本依赖网络下载,但系统刚启动时 Wi-Fi 尚未连接。
解决方案是在[Unit]中增加更强的依赖:
After=network-online.target Wants=network-online.targetnetwork-online.target会等待网络真正可用,比network.target更可靠。
### 5.4 如何让脚本后台运行而不阻塞?
如果你的脚本本身会前台驻留(如 mjpg_streamer),没问题。
但如果脚本执行完就退出,而你想让它持续运行(比如每10秒检测一次),请在脚本内加循环:
#!/bin/bash while true; do python3 /home/pi/check_sensor.py sleep 10 done不要用nohup &或screen,那会破坏 systemd 对进程的掌控。
6. 总结:用 systemd 管理脚本才是专业做法
当你面对多个开机启动脚本时,千万不要图省事全塞进rc.local或写成一个大 shell 脚本。那样一旦出错,排查困难,也无法精细控制。
正确的工程化思路是:
一 script,一 service,独立管理,清晰可控
### 6.1 关键步骤回顾
- 编写脚本并赋予可执行权限
- 创建
.service文件,放在/etc/systemd/system/ - 正确设置
After、User、Restart等关键参数 - 执行
daemon-reload重载配置 - 使用
enable开启自启,start测试运行 - 用
status和journalctl观察状态和日志
### 6.2 推荐命名规范
为了便于管理,建议 service 名称与脚本名保持一致:
| 脚本路径 | Service 名称 |
|---|---|
/home/pi/start-web.sh | start-web.service |
/opt/scripts/init-db.sh | init-db.service |
/usr/local/bin/watchdog.sh | watchdog.service |
统一命名,一看就知道谁是谁。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。