如何在系统启动20秒后运行bash脚本?或实现程序启动后执行脚本
嗨Elias,针对你的问题,我整理了几个实用的方案,帮你搞定脚本在系统启动时的执行时机问题~
方案1:快速实现固定延迟启动
这是你最初想到的思路,操作起来很简单,有两种方式可选:
- 修改脚本本身:直接在
task.sh的开头加入延迟命令,让脚本先等一会儿再执行核心逻辑:
#!/bin/bash sleep 30 # 延迟30秒,可根据实际情况调整时长 # 以下是你的原有脚本内容 stop_target_program mount_raspberry_pi start_target_program
- 用systemd服务管理延迟:如果不想修改脚本,可以通过systemd的前置指令来实现延迟。先创建一个
task.service文件,放到/etc/systemd/system/目录下:
[Unit] Description=Run task.sh after system boot After=multi-user.target # 确保在系统进入多用户环境后执行 [Service] Type=oneshot # 表示服务只执行一次 ExecStartPre=/bin/sleep 30 # 执行脚本前先睡30秒 ExecStart=/path/to/your/task.sh # 替换成你实际的脚本路径 RemainAfterExit=yes [Install] WantedBy=multi-user.target
然后执行以下命令启用服务:
sudo systemctl daemon-reload sudo systemctl enable task.service
这种方式的缺点是延迟时间固定,如果目标程序启动速度不稳定,可能会出现脚本执行时程序还没起来,或者白白浪费等待时间的情况。
方案2:更可靠的「等待目标程序启动后再执行」
你担心的「程序重启后脚本会再次触发重启」其实是可以避免的——只要让脚本只在系统启动时执行一次,而不是程序每次启动都触发。用systemd的oneshot类型服务就能做到这一点,同时我们可以让脚本主动等待目标程序完全启动后再操作。
方式A:脚本内轮询等待进程
修改你的task.sh,加入等待逻辑,直到目标程序运行起来再执行后续操作:
#!/bin/bash # 替换成你的目标程序的进程名(比如nginx、python3等) TARGET_PROCESS="your_target_program_name" # 最大等待时长,防止无限等待 MAX_WAIT=60 elapsed_time=0 echo "Waiting for $TARGET_PROCESS to start..." # 循环检查进程是否存在 while ! pgrep -x "$TARGET_PROCESS" > /dev/null; do sleep 1 elapsed_time=$((elapsed_time + 1)) if [ $elapsed_time -ge $MAX_WAIT ]; then echo "Timeout: $TARGET_PROCESS didn't start within $MAX_WAIT seconds." exit 1 fi done echo "$TARGET_PROCESS is running, starting task..." # 以下是你的原有脚本内容 stop_target_program mount_raspberry_pi start_target_program
然后对应的task.service可以去掉延迟,保持如下配置即可:
[Unit] Description=Run task.sh after target program starts After=multi-user.target [Service] Type=oneshot ExecStart=/path/to/your/task.sh RemainAfterExit=yes [Install] WantedBy=multi-user.target
这样脚本只会在系统启动时执行一次,不会因为后续程序重启而再次触发,完美解决你担心的循环问题。
方式B:利用systemd服务依赖(最推荐)
如果你的目标程序本身是用systemd服务管理的(比如有target_program.service文件),那这是最可靠的方式——直接让你的脚本服务依赖目标程序服务,systemd会自动等待目标程序完全启动后再执行你的脚本。
修改task.service的[Unit]部分:
[Unit] Description=Run task.sh after target program starts After=multi-user.target target_program.service # 明确依赖目标程序服务 Requires=target_program.service # 确保目标程序服务启动成功才执行本服务 [Service] Type=oneshot ExecStart=/path/to/your/task.sh RemainAfterExit=yes [Install] WantedBy=multi-user.target
这种方式完全不需要手动设置延迟或者轮询,由systemd帮你管理启动顺序,是Linux系统启动管理的标准做法,稳定性拉满。
总结
- 临时测试用固定延迟的方式最快捷;
- 长期使用优先选择systemd服务依赖的方式,这是最稳定的方案;
- 如果目标程序没有对应的systemd服务,就用脚本内轮询进程的方式,配合oneshot服务也能完美避免循环触发的问题。
内容的提问来源于stack exchange,提问作者Elias Schuhmacher
相关产品推荐
相关产品推荐

