最近搭建了一个分布式的文件系统,替换以前的云存储需要导很多数据,金大侠在他的机器上跑的脚本,但是他是在前台跑的,后来他电脑待机了,结果可想而知。
因为通过ssh连到服务器上跑脚本,默认都是sshd的子进程(通过 pstree
可以看到),当ssh断开之后,这些子进程都会接到hup信号而终止。所以跑脚本就一定要后台去跑。
在linux上让进程在后台运行的方式也挺多的。
nohup/setsid/&
如果只是临时有一个命令需要长时间运行,什么方法能最简便的保证它在后台稳定运行呢?
我们知道,当用户注销(logout)或者网络断开时,终端会收到 HUP(hangup)信号从而关闭其所有子进程。 因此,我们的解决办法就有两种途径:要么让进程忽略 HUP 信号,要么让进程运行在新的会话里从而成为不属于此终端的子进程。
比如 nohup SOME_COMMAND &
就是在后台运行命令,并且禁掉hup信号。标准输出和错误输出都在nohup.out文件中,也可用">filename 2>&1"来更改缺省的重定向文件名。
命令 setsid SOME_COMMAND
让当前进程不再是终端的子进程,所以也可以稳定的在后台运行。
命令 (SOME_COMMAND &)
也是通过让进程不再是终端的子进程而不受当前终端的hup信号影响。
disown
如果命令已经在跑着了,那么想让它在后台去安稳运行怎么办呢?
那就可以用 disown
命令。
- 用disown -h jobspec来使某个作业忽略HUP信号
- 用disown -ah 来使所有的作业都忽略HUP信号
- 用disown -rh 来使正在运行的作业忽略HUP信号
需要注意的是,当使用过 disown 之后,会将把目标作业从作业列表中移除,我们将不能再使用jobs来查看它,但是依然能够用ps -ef查找到它。
如果进程实在前台运行的,那就可以先通过Ctrl-z将进程suspend,然后通过 jobs
命令查看它的作业号,然后在通过 bg
命令扔到后台运行,最后在 disown
一下。
screen
当然,最好的跑脚本的方式是通过 screen
命令,就像东颖说得,用screen跑脚本是程序员的基本素质。
简单的说,screen 提供了 ANSI/VT100 的终端模拟器,使它能够在一个真实终端下运行多个全屏的伪终端。
基本命令为:
- 用screen -dmS session name来建立一个处于断开模式下的会话(并指定其会话名)
- 用screen -list 来列出所有会话
- 用screen -r session name来重新连接指定会话
- 用快捷键CTRL-a d 来暂时断开当前会话
通过screen执行的进程,它的父进程是screen而不是sshd,所以当ssh断开时也不会有影响。