更好的方法:
https://askubuntu.com/questions/48321/how-do-i-start-applications-automatically-on-login
Non GUI approach
Advanced users may want to manually put a .desktop file in ~/.config/autostart to run applications after a user login. This may have following content:
[Desktop Entry]
Type=Application
Name=<Name of application as displayed>
Exec=<command to execute>
Icon=<full path to icon>
Comment=<optinal comments>
X-GNOME-Autostart-enabled=true
如果要执行python程序,需要在python脚本里写上 #!/usr/bin/python 注释,表明是python程序。
比如要执行 testprocess.py ,其代码如下:
#!/usr/bin/python3
...
再创建一个shell 脚本文件 testprocess.sh,里面内容为,(为啥创建这个文件,似乎是 ~/.config/autostart/***.desktop 自动运行脚本只能执行shell script,不能执行可执行文件也不能执行python脚本文件):
#!/bin/sh
/home/nx/hzh/testprocess.py
最后其自动运行脚本如下 ~/.config/autostart/***.desktop (自动运行脚本似乎只能执行shell script):
[Desktop Entry]
Type=Application
Name=monitor arm
Exec=/home/nx/hzh/testprocess2.sh
NoDisplay=true
# X-GNOME-Autostart-enabled=true
http://askubuntu.com/questions/9382/how-can-i-configure-a-service-to-run-at-startup
http://stackoverflow.com/questions/7221757/run-automatically-program-on-startup-under-linux-ubuntu
sudo mv /filename /etc/init.d/
sudo chmod +x /etc/init.d/filename
sudo update-rc.d filename defaults
Script should now start on boot. Note that this method also works with both hard links and symbolic links (ln
).
Edit
At this point in the boot process PATH isn't set yet, so it is critical that absolute paths are used throughout. BUT, as pointed out in the comments by Steve HHH, explicitly declaring the full file path (/etc/init.d/filename
) for the update-rc.d command is not valid in most versions of Linux. Per the manpage for update-rc.d, the second parameter is a script located in /etc/init.d/*
. Updated above code to reflect this.
Another Edit
Also as pointed out in the comments (by Charles Brandt), /filename
must be an init style script. A good template was also provided - https://github.com/fhd/init-script-template.
Another link to another article just to avoid possible link rot (although it would be saddening if GitHub died) - http://www.linux.com/learn/tutorials/442412-managing-linux-daemons-with-init-scripts
yetAnother Edit
As pointed out in the comments (by Russell Yan), This works only on default mode of update-rc.d.
According to manual of update-rc.d, it can run on two modes, "the machines using the legacy mode will have a file /etc/init.d/.legacy-bootordering
", in which case you have to pass sequence and runlevel configuration through command line arguments.
The equivalent argument set for the above example is
sudo update-rc.d filename start 20 2 3 4 5 . stop 20 0 1 6 .
- To start a daemon at startup:
update-rc.d service_name defaults
- To remove:
update-rc.d -f service_name remove
defaults => default run levels 2,3,4 and 5
Example:
update-rc.d tomcat7 defaults
1) 将你的启动脚本复制到 /etc/init.d目录下
以下假设你的脚本文件名为 test。
2) 设置脚本文件的权限
$ sudo chmod 755 /etc/init.d/test
3) 执行如下命令将脚本放到启动脚本中去:
$ cd /etc/init.d
$ sudo update-rc.d example_name.sh defaults 95
注:其中数字95是脚本启动的顺序号,按照自己的需要相应修改即可。在你有多个启动脚本,而它们之间又有先后启动的依赖关系时你就知道这个数字的具体作用了。该命令的输出信息参考如下:
update-rc.d: warning: /etc/init.d/example_name.sh missing LSB information
update-rc.d: see <http://wiki.debian.org/LSBInitScripts>
Adding system startup for /etc/init.d/test ...
/etc/rc0.d/K95example_name.sh -> ../init.d/example_name.sh
/etc/rc1.d/K95example_name.sh -> ../init.d/example_name.sh
/etc/rc6.d/K95example_name.sh -> ../init.d/example_name.sh
/etc/rc2.d/S95example_name.sh -> ../init.d/example_name.sh
/etc/rc3.d/S95example_name.sh -> ../init.d/example_name.sh
/etc/rc4.d/S95example_name.sh -> ../init.d/example_name.sh
/etc/rc5.d/S95example_name.sh -> ../init.d/example_name.sh
卸载启动脚本的方法:
$ cd /etc/init.d
$ sudo update-rc.d -f example_name.sh
命令输出的信息参考如下:
Removing any system startup links for /etc/init.d/test ...
/etc/rc0.d/K95example_name.sh
/etc/rc1.d/K95example_name.sh
/etc/rc2.d/S95example_name.sh
/etc/rc3.d/S95example_name.sh
/etc/rc4.d/S95example_name.sh
/etc/rc5.d/S95example_name.sh
/etc/rc6.d/K95example_name.sh
按指定顺序、在指定运行级别中启动或关闭
用法:
update-rc.d <basename> start|stop <order> <runlevels>
例:
# update-rc.d ushare start 20 2 3 4 5 . stop 20 0 1 6 .
解析:表示在2、3、4、5这五个运行级别中,由小到大,第20个开始运行ushare;在 0 1 6这3个运行级别中,第20个关闭apachectl。
注意它有2个点号,其效果等于下面方法:
# update-rc.d ushare defaults
设置启动和关闭顺序为80,20, 级别为默认值:
# update-rc.d <basename> defaults 80 20
-------------------------------------------------------------
linux中的init版本介绍:
init类型 | 说明 | 识别 |
Systemd | 新出现的init,很多linux发行版都已经或者计划转向Systemd | 如果你的系统目录文件中/usr/lib/systemd和/etc/systemd,说明你有systemd,ubuntu自从15.04版本以后都使用了systemd |
Upstart | ubuntu曾经使用的init,但是现在已经转向了systemd | 系统目录有/etc/init,而且其中有许多conf文件,说明你的系统有upstart(除非你的系统是debian7,那说明你使用的是System V init),同时,ubuntu 17.10也有这个目录,我猜测可能是为了兼容(此处存疑问,现在的ubuntu的init确实是systemd) |
System V init | 传统的init,大多数的linux发行版都会兼容 | 系统有/etc/inittab文件,说明你很可能是System V init |
update-rc.d 命令
- 说明:安装或者移除 System-V init的脚本连接(可以理解为指向脚本的快捷方式,即
/etc/rc*runlevel*.d/NNname => /etc/init.d/name)
。你可以通过runlevel
命令查看当前的运行级别,runlevel的概念网上一大堆就不提及了。简单来说,假如我的机器开机默认会进入runlevel为5的空间(ubuntu图形界面),那么就会在开机后执行/etc/rc5.d/*下所有的脚本(这样描述有些误差,其实此目录下都是软链接,指向/etc/init.d/下相对应的脚本)。另外,你还会发现这些链接的命名规则很有意思,一般来说,K开头的链接是关闭这个服务,而S开头的才是启动这个服务。此时应该有疑问,为什么链接都是指向同一个脚本,但是功能确是截然相反?网上有人说是这两个字母给脚本传递了不同的参数,但其实这个过程怎么实现我还不是很清楚(可以cat一下/etc/init.d/rsyslog的内容,这个shell脚本思路还是很清晰的,先是定义了各种函数,然后通过参数$1运用case语句来调用不同的函数,此时你会发现service serv_name COMMAND
其实和/etc/init.d/serv_name COMMAND
是一样的) - 简单来说,你可以通过此命令控制开机自启动服务。
- 开机启动服务(建立软链接):
update-rc.d foobar defaults
- 移除所有软链接:
update-rc.d foobar remove
- 关闭开机启动服务:
update-rc.d foobar disable
- 重新开启开机启动服务:
update-rc.d foobar enable
Systemd介绍: (以下内容大部分来自 http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html, http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-part-two.html)
历史上,Linux 的启动一直采用init
进程。
下面的命令用来启动服务。
$ sudo /etc/init.d/apache2 start
# 或者
$ service apache2 start
这种方法有两个缺点。
一是启动时间长。init
进程是串行启动,只有前一个进程启动完,才会启动下一个进程。
二是启动脚本复杂。init
进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种情况,这往往使得脚本变得很长。
Systemd 就是为了解决这些问题而诞生的。它的设计目标是,为系统的启动和管理提供一套完整的解决方案。Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面。
systemctl
是 Systemd 的主命令,用于管理系统。
systemd-analyze
命令用于查看启动耗时。
hostnamectl
命令用于查看当前主机的信息。
localectl
命令用于查看本地化设置。
timedatectl
命令用于查看当前时区设置。
loginctl
命令用于查看当前登录的用户。
Unit
Systemd 可以管理所有系统资源。不同的资源统称为 Unit,unit可以叫做服务单元。
Unit 一共分成12种。
- Service unit:系统服务
- Target unit:多个 Unit 构成的一个组
- Device Unit:硬件设备
- Mount Unit:文件系统的挂载点
- Automount Unit:自动挂载点
- Path Unit:文件或路径
- Scope Unit:不是由 Systemd 启动的外部进程
- Slice Unit:进程组
- Snapshot Unit:Systemd 快照,可以切回某个快照
- Socket Unit:进程间通信的 socket
- Swap Unit:swap 文件
- Timer Unit:定时器
systemctl list-units
命令可以查看当前系统的所有 Unit 。
systemctl status
命令用于查看系统状态和单个 Unit 的状态。
除了status
命令,systemctl
还提供了三个查询状态的简单方法,主要供脚本内部的判断语句使用。
# 显示某个 Unit 是否正在运行
$ systemctl is-active application.service
# 显示某个 Unit 是否处于启动失败状态
$ systemctl is-failed application.service
# 显示某个 Unit 服务是否建立了启动链接
$ systemctl is-enabled application.service
最常用的是下面这些命令,用于启动和停止 Unit(主要是 service):
# 立即启动一个服务
$ sudo systemctl start apache.service
# 立即停止一个服务
$ sudo systemctl stop apache.service
# 重启一个服务
$ sudo systemctl restart apache.service
# 杀死一个服务的所有子进程
$ sudo systemctl kill apache.service
# 重新加载一个服务的配置文件
$ sudo systemctl reload apache.service
# 重载所有修改过的配置文件
$ sudo systemctl daemon-reload
# 显示某个 Unit 的所有底层参数
$ systemctl show httpd.service
# 显示某个 Unit 的指定属性的值
$ systemctl show -p CPUShares httpd.service
# 设置某个 Unit 的指定属性
$ sudo systemctl set-property httpd.service CPUShares=500
Target
启动计算机的时候,需要启动大量的 Unit。如果每一次启动,都要一一写明本次启动需要哪些 Unit,显然非常不方便。Systemd 的解决方案就是 Target。
简单说,Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候,Systemd 就会启动里面所有的 Unit。
传统的init
启动模式里面,有 RunLevel 的概念,跟 Target 的作用很类似。不同的是,RunLevel 是互斥的,不可能多个 RunLevel 同时启动,但是多个 Target 可以同时启动。
Target 与 传统 RunLevel 的对应关系如下。
Traditional runlevel New target name Symbolically linked to...
Runlevel 0 | runlevel0.target -> poweroff.target
Runlevel 1 | runlevel1.target -> rescue.target
Runlevel 2 | runlevel2.target -> multi-user.target
Runlevel 3 | runlevel3.target -> multi-user.target
Runlevel 4 | runlevel4.target -> multi-user.target
Runlevel 5 | runlevel5.target -> graphical.target
Runlevel 6 | runlevel6.target -> reboot.target
它与init
进程的主要差别如下。
(1)默认的 RunLevel(在
/etc/inittab
文件设置)现在被默认的 Target 取代,位置是/etc/systemd/system/default.target
,通常符号链接到graphical.target
(图形界面)或者multi-user.target
(多用户命令行)。(2)启动脚本的位置,以前是
/etc/init.d
目录,符号链接到不同的 RunLevel 目录 (比如/etc/rc3.d
、/etc/rc5.d
等),现在则存放在/lib/systemd/system
和/etc/systemd/system
目录。(3)配置文件的位置,以前
init
进程的配置文件是/etc/inittab
,各种服务的配置文件存放在/etc/sysconfig
目录。现在的配置文件主要存放在/lib/systemd
目录,在/etc/systemd
目录里面的修改可以覆盖原始设置。
日志管理
Systemd 统一管理所有 Unit 的启动日志。带来的好处就是,可以只用journalctl
一个命令,查看所有日志(内核日志和应用日志)。日志的配置文件是/etc/systemd/journald.conf
。
journalctl
功能强大,用法非常多。
# 查看所有日志(默认情况下 ,只保存本次启动的日志)
$ sudo journalctl
# 查看内核日志(不显示应用日志)
$ sudo journalctl -k
# 查看系统本次启动的日志
$ sudo journalctl -b
$ sudo journalctl -b -0
# 查看上一次启动的日志(需更改设置)
$ sudo journalctl -b -1
# 查看指定时间的日志
$ sudo journalctl --since="2012-10-30 18:17:16"
$ sudo journalctl --since "20 min ago"
$ sudo journalctl --since yesterday
$ sudo journalctl --since "2015-01-10" --until "2015-01-11 03:00"
$ sudo journalctl --since 09:00 --until "1 hour ago"
# 显示尾部的最新10行日志
$ sudo journalctl -n
# 显示尾部指定行数的日志
$ sudo journalctl -n 20
# 实时滚动显示最新日志
$ sudo journalctl -f
# 查看指定服务的日志
$ sudo journalctl /usr/lib/systemd/systemd
# 查看指定进程的日志
$ sudo journalctl _PID=1
# 查看某个路径的脚本的日志
$ sudo journalctl /usr/bin/bash
# 查看指定用户的日志
$ sudo journalctl _UID=33 --since today
# 查看某个 Unit 的日志
$ sudo journalctl -u nginx.service
$ sudo journalctl -u nginx.service --since today
# 实时滚动显示某个 Unit 的最新日志
$ sudo journalctl -u nginx.service -f
# 合并显示多个 Unit 的日志
$ journalctl -u nginx.service -u php-fpm.service --since today
# 查看指定优先级(及其以上级别)的日志,共有8级
# 0: emerg
# 1: alert
# 2: crit
# 3: err
# 4: warning
# 5: notice
# 6: info
# 7: debug
$ sudo journalctl -p err -b
# 日志默认分页输出,--no-pager 改为正常的标准输出
$ sudo journalctl --no-pager
# 以 JSON 格式(单行)输出
$ sudo journalctl -b -u nginx.service -o json
# 以 JSON 格式(多行)输出,可读性更好
$ sudo journalctl -b -u nginx.serviceqq
-o json-pretty
# 显示日志占据的硬盘空间
$ sudo journalctl --disk-usage
# 指定日志文件占据的最大空间
$ sudo journalctl --vacuum-size=1G
# 指定日志文件保存多久
$ sudo journalctl --vacuum-time=1years
systemd的启动
对于那些支持 Systemd 的软件,安装的时候,会自动在/usr/lib/systemd/system
目录添加一个配置文件。
如果你想让该软件开机启动,就执行下面的命令(以httpd.service
为例)。
$ sudo systemctl enable httpd
上面的命令相当于在/etc/systemd/system
目录添加一个符号链接,指向/usr/lib/systemd/system
里面的httpd.service
文件。
这是因为开机时,Systemd
只执行/etc/systemd/system
目录里面的配置文件。这也意味着,如果把修改后的配置文件放在该目录,就可以达到覆盖原始配置的效果。
启动类型
Type
字段定义启动类型。它可以设置的值如下。
- simple(默认值):
ExecStart
字段启动的进程为主进程- forking:
ExecStart
字段将以fork()
方式启动,此时父进程将会退出,子进程将成为主进程- oneshot:类似于
simple
,但只执行一次,Systemd 会等它执行完,才启动其他服务- dbus:类似于
simple
,但会等待 D-Bus 信号后启动- notify:类似于
simple
,启动结束后会发出通知信号,然后 Systemd 再启动其他服务- idle:类似于
simple
,但是要等到其他任务都执行完,才会启动该服务。一种使用场合是为让该服务的输出,不与其他服务的输出相混合
重启行为
Service
区块有一些字段,定义了重启行为。
KillMode
字段:定义 Systemd 如何停止 sshd 服务。
上面这个例子中,将KillMode
设为process
,表示只停止主进程,不停止任何sshd 子进程,即子进程打开的 SSH session 仍然保持连接。这个设置不太常见,但对 sshd 很重要,否则你停止服务的时候,会连自己打开的 SSH session 一起杀掉。
KillMode
字段可以设置的值如下。
- control-group(默认值):当前控制组里面的所有子进程,都会被杀掉
- process:只杀主进程
- mixed:主进程将收到 SIGTERM 信号,子进程收到 SIGKILL 信号
- none:没有进程会被杀掉,只是执行服务的 stop 命令。
接下来是Restart
字段。
Restart
字段:定义了 sshd 退出后,Systemd 的重启方式。
上面的例子中,Restart
设为on-failure
,表示任何意外的失败,就将重启sshd。如果 sshd 正常停止(比如执行systemctl stop
命令),它就不会重启。
Restart
字段可以设置的值如下。
- no(默认值):退出后不会重启
- on-success:只有正常退出时(退出状态码为0),才会重启
- on-failure:非正常退出时(退出状态码非0),包括被信号终止和超时,才会重启
- on-abnormal:只有被信号终止和超时,才会重启
- on-abort:只有在收到没有捕捉到的信号终止时,才会重启
- on-watchdog:超时退出,才会重启
- always:不管是什么退出原因,总是重启
对于守护进程,推荐设为on-failure
。对于那些允许发生错误退出的服务,可以设为on-abnormal
。
最后是RestartSec
字段。
RestartSec
字段:表示 Systemd 重启服务之前,需要等待的秒数。上面的例子设为等待42秒。
[Install] 区块
Install
区块,定义如何安装这个配置文件,即怎样做到开机启动。
WantedBy
字段:表示该服务所在的 Target。
Target
的含义是服务组,表示一组服务。WantedBy=multi-user.target
指的是,sshd 所在的 Target 是multi-user.target
。
这个设置非常重要,因为执行systemctl enable sshd.service
命令时,sshd.service
的一个符号链接,就会放在/etc/systemd/system
目录下面的multi-user.target.wants
子目录之中。
Systemd 有默认的启动 Target。
$ systemctl get-default multi-user.target
上面的结果表示,默认的启动 Target 是multi-user.target
。在这个组里的所有服务,都将开机启动。这就是为什么systemctl enable
命令能设置开机启动的原因。
使用 Target 的时候,systemctl list-dependencies
命令和systemctl isolate
命令也很有用。
# 查看 multi-user.target 包含的所有服务 $ systemctl list-dependencies multi-user.target # 切换到另一个 target # shutdown.target 就是关机状态 $ sudo systemctl isolate shutdown.target
一般来说,常用的 Target 有两个:一个是multi-user.target
,表示多用户命令行状态;另一个是graphical.target
,表示图形用户状态,它依赖于multi-user.target
。官方文档有一张非常清晰的 Target 依赖关系图。
Target 的配置文件
Target 也有自己的配置文件。
$ systemctl cat multi-user.target [Unit] Description=Multi-User System Documentation=man:systemd.special(7) Requires=basic.target Conflicts=rescue.service rescue.target After=basic.target rescue.service rescue.target AllowIsolate=yes
注意,Target 配置文件里面没有启动命令。
上面输出结果中,主要字段含义如下。
Requires
字段:要求basic.target
一起运行。
Conflicts
字段:冲突字段。如果rescue.service
或rescue.target
正在运行,multi-user.target
就不能运行,反之亦然。
After
:表示multi-user.target
在basic.target
、rescue.service
、rescue.target
之后启动,如果它们有启动的话。
AllowIsolate
:允许使用systemctl isolate
命令切换到multi-user.target
。
修改配置文件后重启
修改配置文件以后,需要重新加载配置文件,然后重新启动相关服务。
# 重新加载配置文件 $ sudo systemctl daemon-reload # 重启相关服务 $ sudo systemctl restart foobar
systemd实现开机启动某程序软件
https://www.howtogeek.com/687970/how-to-run-a-linux-program-at-startup-with-systemd/
Creating the Service Program
We need to have a program that systemd
will launch. We’ll create a simple script, called “htg.sh”. This tutorial uses the Gedit text editor, but you can use whatever text editor you prefer.
touch htg.sh
gedit htg.sh
The gedit
editor will open. Copy and paste the following text into the editor.
#!/bin/bash
echo "htg.service: ## Starting ##" | systemd-cat -p info
while :
do
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
echo "htg.service: timestamp ${TIMESTAMP}" | systemd-cat -p info
sleep 60
done
We’ll copy the script to the /usr/local/bin
directory.
sudo cp htg.sh /usr/local/bin
And we need to make it executable:
sudo chmod +x /usr/local/bin/htg.sh
Creating the Service Unit File
list the service for show:
sudo systemctl list-unit-files --type-service
Our service is going to be called “htg.service”. No unit files have that name, so we can proceed and create our unit file.
sudo gedit /etc/systemd/system/htg.service
The gedit
editor will open. Copy and paste the following text into the editor:
[Unit]
Description=How-To Geek Service Example
Wants=network.target
After=syslog.target network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/htg.sh
Restart=on-failure
RestartSec=10
KillMode=process
[Install]
WantedBy=multi-user.target
This command will give the owner read and write permissions, and read permissions to the group. Others will have no permissions.
sudo chmod 640 /etc/systemd/system/htg.service
We can have systemctl
check the syntax of our unit file for us, even if the service isn’t running yet. Any errors will be reported. (Actually, the “.service” part is optional for most commands.)
systemctl status htg.service
Starting the Service
When you add a new unit file or edit an existing one, you must tell systemd
to reload the unit file definitions.
sudo systemctl daemon-reload
If you want a service to be launched at startup you must enable it:
sudo systemctl enable htg
Enabling a service doesn’t start it, it only sets it to be launched at boot time. To start the service now, you must use systemctl
with the start
option.
sudo systemctl start htg
Verifying the Service
After manually starting the service or after rebooting the computer, we can verify that our service is running correctly.
sudo systemctl status htg.service
Stopping and Disabling the Service
If you need to stop the service, you can do so with this command:
sudo systemctl stop htg.service
This stops the service, but it doesn’t prevent it from restarting next time the computer is rebooted. To stop the service being launched at startup, you need to disable it:
sudo systemctl disable htg.service
下面是一个较完整的示例:
https://askubuntu.com/questions/919054/how-do-i-run-a-single-command-at-startup-using-systemd
[Unit]
Description=Apache Spark Master and Slave Servers
After=network.target
After=systemd-user-sessions.service
After=network-online.target
[Service]
User=spark
Type=forking
ExecStart=/opt/spark-1.6.1-bin-hadoop2.6/sbin/start-all.sh
ExecStop=/opt/spark-1.6.1-bin-hadoop2.6/sbin/stop-all.sh
TimeoutSec=30
Restart=on-failure
RestartSec=30
StartLimitInterval=350
StartLimitBurst=10
[Install]
WantedBy=multi-user.target