如何在启动时运行shell脚本

498
Amazon S3 Linux实例上,我有两个脚本,称为start_my_appstop_my_app,它们启动和停止forever(进而运行我的Node.js应用程序)。我使用这些脚本手动启动和停止我的Node.js应用程序。到目前为止还不错。
我的问题是:我还想设置这样的配置,即每当系统启动时都运行start_my_app。我知道我需要在init.d中添加一个文件,并且我知道如何将其链接到rc.d中的适当目录,但我无法弄清楚实际上需要放在init.d中的文件。我认为它应该只是一行,例如start_my_app,但这对我没有起作用。

5
жҲ‘дёҚжҳҜиҝҷз§ҚдёңиҘҝзҡ„专家пјҢдҪҶжҲ‘и®Өдёәinit.dи§ЈеҶіж–№жЎҲпјҲиҝҷйҮҢпјүеә”иҜҘжҜ”rc.localи§ЈеҶіж–№жЎҲжӣҙеҸҜеҸ–пјҢеӣ дёәеҗҺиҖ…жҳҜж—§е·Ҙе…·пјҢеҸӘиғҪ继з»ӯдҪҝз”ЁжҳҜеӣ дёәж–°е·Ҙе…·е…·жңүеҗ‘еҗҺе…је®№жҖ§гҖӮ - erikbstack
pm2启动我的应用; pm2启动; pm2保存 - Unitech
在Raspbian中,有一个.config/lxsession/LXDE-pi/autostart文件,对我来说效果更好 - 其他操作系统中是否有类似的文件?它对我更有效的原因是rc.local执行时并不会初始化所有内容(在我的情况下是apache),而autostart是用户会话的开始,因此几乎所有内容都应该在那时初始化。 - Chiwda
23个回答

534

首先在 /home/user/startup.sh 创建你的开机启动脚本,并确保它可执行

chmod +x /home/user/startup.sh
然后为它设置一个 crontab:
$ crontab -e
@reboot  /home/user/startup.sh

现在你的 startup.sh 脚本将在每次启动时运行。


9
这是唯一一个对我非常有效且没有麻烦的解决方案!谢谢。 - whoopididoo
46
这是最佳解决方案,将 @reboot sh $HOME/test.sh 添加到 crontab 中甚至更加简洁。 - user3667089
8
@user3667089 实际上,它没有生效。我打开终端,输入“crontab -e”,出现一个窗口,在其中写入“@reboot sh /home/user/test.sh”,但它在启动时没有运行。我做错了什么? - MycrofD
5
@MycrofD,你的 crontab -l 应该显示 @reboot sh $HOME/test.sh 以确认它是否已经设置。 - user3667089
10
在Ubuntu中,您需要执行以下操作:@reboot root sh script.sh - Jurass
显示剩余10条评论

350

你放在/etc/init.d/中的文件必须设置为可执行:

chmod +x /etc/init.d/start_my_app

如@meetamit所指出,如果仍无法运行,您可能需要在/etc/rc.d/中创建一个符号链接到该文件。
ln -s /etc/init.d/start_my_app /etc/rc.d/

请注意,在最新版本的Debian上,这将不起作用,因为您的脚本必须符合LSB(Linux标准库)规范(至少提供以下操作:start、stop、restart、force-reload和status): https://wiki.debian.org/LSBInitScripts 另外,您应该始终在脚本中使用文件的绝对路径而不是相对路径,这可能会解决意外问题。
/var/myscripts/start_my_app

最后,确保你在文件的顶部包含了shebang。
#!/bin/sh

10
我做了这件事,但它没有运行。它是否会自动运行,只因为它在 /etc/init.d 中,还是我需要额外做些什么来安排它在系统启动时运行? - amphibient
6
@amphibient 还不太够... 你还需要使用 ln 命令,将此文件创建符号链接到 rc.d 目录内的一个目录中。 - meetamit
30
我的根目录下的etc文件夹里面没有rc.d目录,这让我感到困惑。Linux需要这个目录才能启动吧?但是我的系统好像没有问题。我需要自己创建这个目录吗?我看到一堆类似"rc1.d"到"rc5.d"的文件。 - OKGimmeMoney
6
我没有任何/etc/rc.d文件夹,但我有/etc/rcX.d文件夹(例如/etc/rc0.d/etc/rc1.d/etc/rcS.d),同时还有一个文件/etc/rc.local。我认为您应该在自定义文件夹(如/etc/rc9.d)或现有文件夹之一中创建符号链接... (Ubuntu Server 14.04) - Artfaith
3
这个问题对我有所帮助:http://unix.stackexchange.com/questions/28679/whats-the-connection-between-etc-init-d-and-etc-rcx-d-directories-in-linux - seth10
显示剩余8条评论

129

一个简单的方法是在/etc/rc.local文件中添加一行:

/PATH/TO/MY_APP &

或者,如果你想以特定的用户身份运行命令:

su - USER_FOOBAR -c /PATH/TO/MY_APP &
(the trailing ampersand backgrounds the process and allows the rc.local to continue executing)
如果你想要完整的init脚本,Debian发行版有一个模板文件,所以:
(末尾的&符号将进程放到后台执行,并允许rc.local继续执行)
cp /etc/init.d/skeleton /etc/init.d/your_app

并对其进行一些调整。


2
谢谢!考虑到简单的需求,这种方法最有效。我相当确定我需要指定用户,否则当需要手动停止应用程序(通过运行stop_my_app)时,我必须使用sudo,不是吗?此外,我想知道尾随的“&”符号的确切功能是什么。 - meetamit
3
用户依赖于您的应用程序。但是如果没有必要作为root运行,请避免这样做。使用&将进程在后台运行。 - Gilles Quénot
2
Sputnick,抱歉,但我必须将Koren的答案标记为被接受的答案,主要是因为@erikb85指出的原因,但也因为我的原始问题要求使用init.d方式进行操作(您的答案只是当时对我来说更简单的解决方法)。这篇文章获得了很多浏览量和投票,因此保持准确性非常重要。 - meetamit
4
似乎没有提到末尾的&符号使进程在后台运行,并允许rc.local继续执行。 - mchicago
谢谢!我花了几个小时试图创建一个服务,但是一直不成功,一直在碰壁。尝试了这个方法,结果非常好! - Marko Gresak
显示剩余2条评论

39

这是我在 Red Hat Linux 系统上的操作方式。

将您的脚本放置在 /etc/init.d 中,所有权为 root 并可执行。在脚本顶部,您可以为 chkconfig 提供指令。例如,下面的脚本用于以 oracle 用户身份启动一个 Java 应用程序。

脚本的名称为 /etc/init.d/apex

#!/bin/bash
# chkconfig: 345 99 10
# Description: auto start apex listener
#
case "$1" in
 'start')
   su - oracle -c "cd /opt/apex ; java -jar apex.war > logs/apex.log 2>logs/apex_error.log &";;
 'stop')
   echo "put something to shutdown or kill the process here";;
esac

这意味着此脚本必须在3、4和5级别下运行,启动/停止的优先级分别为99和10。

然后,作为用户root,您可以使用chkconfig在启动时启用或禁用该脚本:

chkconfig --list apex
chkconfig --add apex

你可以使用 service start/stop apex 命令。


与此同时,我已经尝试了一个名为supervisord的软件包(http://supervisord.org/),它可以在epel存储库中找到。它可以用于启动程序并监控它们,在失败时重新启动它们。 - Saule
在将脚本放入 /etc/init.d/ 文件夹后,您可以键入 "chkconfig service_name on" 而不是键入 "chkconfig --add service_name"。 - Dragan Radevic

36

使用sudo输入cron:

sudo crontab -e

添加一个命令以在启动时运行,本例中为一个脚本:

@reboot sh /home/user/test.sh

保存:

按ESC然后输入:x保存并退出,或者按ESC然后输入ZZ(即shift+zz)

测试测试测试:

  1. 在不使用cron的情况下运行您的测试脚本,确保它实际有效。

  2. 确保您已在cron中保存了您的命令,使用sudo crontab -e

  3. 重新启动服务器以确认所有内容都正常工作,sudo @reboot


1
我非常喜欢这个。谢谢!附注:如果您想在启动时使用当前用户运行某个命令,请不要使用 sudo - Melroy van den Berg
这些信息应该存储在哪里?不是在/tmp目录下吧? - Peter Mortensen
1
根据维基百科,@reboot 并不被广泛支持。 - Sapphire_Brick
它在Ubuntu 18上运行成功了!!!!! - MartianMartian

19

只需在您的crontab中添加一行即可。

确保该文件是可执行的:

chmod +x /path_to_you_file/your_file

编辑crontab文件:

crontab -e

你需要添加的代码行:

@reboot  /path_to_you_file/your_file

就这么简单!


1
这对我没用,我有什么遗漏吗? # uname -a Linux accton-xp70a0-26-a1 3.11.10-301.fc20.x86_64 #1 SMP Thu Dec 5 14:01:17 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux - user5154816
这在我的CentOs 7上有效。对于那些遇到问题的人,我确实需要创建一个shell脚本,使其可执行(chmod +x file_name),并从cron中调用shell脚本,然后调用node path_to_file/index.js。 - SeanOlson

14
另一个选择是在您的crontab中使用@reboot命令。并非所有版本的cron都支持此功能,但如果您的实例基于Amazon Linux AMI,则可以使用此功能。

12

使用nanogedit编辑器编辑/etc/rc.local/etc/rc.d/rc.local文件并将您的脚本添加到其中。

sudo nano /etc/rc.local

这是修改后的内容:

#!/bin/sh
/path-to-your-script/your-scipt-name.sh

完成后按下ctrl+o以更新,然后按Enter再按ctrl+x

使文件可执行。

sudo chmod 755 /etc/rc.local

然后启动rc-local服务,在启动时运行脚本。

sudo systemctl start rc-local

7

你可以做到:

chmod +x PATH_TO_YOUR_SCRIPT/start_my_app 

然后使用这个命令
update-rc.d start_my_app defaults 100

请查看Cyberciti网站上的这个页面,它与Linux如何在启动时运行命令有关。

1
我有一个非常简单的设置,基于Yocto构建,这是使我的脚本工作的唯一方法。谢谢。 - Catalin Vasile

5

很多关于在启动时开始某些操作的答案,但通常您希望稍后启动它,因为您的脚本依赖于例如网络。使用 at 命令来增加延迟时间,例如:

at now + 1 min -f /path/yourscript

您可以在 /etc/rc.local 中添加此内容,也可以在 cron 中添加,例如:

# crontab -e
@reboot at now + 1 min -f /path/yourscript

将cron和at组合起来不是很有趣吗? 相关信息可以在手册 man at 中找到。

至于@reboot可能不被广泛支持的评论,只需试一下即可。 我发现在支持systemd的发行版(如Ubuntu和Raspbian)中,/etc/rc.local已经过时了。


1
@cregox 我在 Raspberry Pi 3 B+ 和 Pi Zero W 上进行了测试,两者均使用 Raspbian,Linux 5.4.51。 - Roland
在 AWS Linux 2 上测试了 iptables 脚本,1 分钟的延迟确实让它起作用。谢谢。 - xs2rashid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接