nohup、&、disown、setsid、screen、jobs 后台运行命令区别
Linux / Unix 系统有许多后台运行命令
例如 nohup、&、disown、setsid、screen、jobs
本文将介绍他们之间的区别和联系
使用场景:
我们经常会碰到这样的问题,用ssh登录了远程的Linux服务器,运行了一些耗时较长的任务,结果却由于网络等的不稳定导致任务中途失败。
这是由于在用户注销(logout)或者网络断开时,终端会收到 HUP(hangup)信号从而关闭其所有子进程。
解决办法有两种:
1)让进程忽略HUP信号,如 nohup、screen
2)让进程运行在新的会话里执行,从而不属于此终端的子进程,如 setsid、(cmd &)
1. nohup
用途:不挂断地运行命令,即退出了终端仍然会在后台运行,常配合&使用。
语法:nohup Command [ Arg … ] [ & ]
无论是否将 nohup 命令的输出重定向到终端,输出都将附加到当前目录的 nohup.out 文件中。
注意点:
1)如果当前目录的 nohup.out 文件不可写,输出重定向到 $HOME/nohup.out 文件中。
2)如果没有文件能创建或打开以用于追加,那么 Command 参数指定的命令不可调用。
退出状态,则该命令返回下列出口值:
126 可以查找但不能调用 Command 参数指定的命令。
127 nohup 命令发生错误或不能查找由 Command 参数指定的命令。
否则,nohup 命令的退出状态是 Command 参数指定命令的退出状态。
nohup 命令,会将标准输出和标准错误默认重写向到nohup.out中,所以可以在命令之后添加上">filename 2>&1",例如把输出重新定向到/mimvp-nohup.log文件中。
nohup ~/mimvp-shell.sh > ~/mimvp-nohup.log 2>&1 &
2. & 和 ()
用途:在后台运行,但有一个问题ssh窗口关闭或网络断开,此后台程序也会停止运行。
原因:当用户注销(logout)或者网络断开时,终端会收到 HUP(hangup)信号从而关闭其所有子进程。
解决办法:让进程忽略HUP信号或者将对应脚本程序设置为不属于此终端的子进程。
一般 nohup 和 & 两者一起配合使用,例如:
nohup command &
另外补充:
&可以结合括号()一起使用,产生一个新的子shell并在此子shell中将任务放置到后台运行,从而不受当前shell终端的HUP信号影响,此用法类似与 setsid,且通过 jobs -l无法查看,即提交的作业不在作业列表里。
使用格式:(COMMAND [ARG]... &)
应用实例:(sh mimvp-shell.sh &)
运行结果:
$ ps -ef | grep mimvp homer 10955 1 0 18:04 pts/5 00:00:00 sh mimvp-shell.sh homer 10956 10955 0 18:04 pts/5 00:00:00 ping mimvp.com homer 10992 10957 0 18:04 pts/24 00:00:00 grep --color=auto mimvp
可见,其父进程id=1,并非当前的终端id,从而不受当前终端影响,关闭并重启终端后,命令会仍然在后台运行,非常类似于 setsid
而我通常的使用方式为:
nohup ./filename.sh > filename.log 2>&1 &
nohup ./filename.sh &> filename.log &
nohup 优于 & 的三点理由:
1) nohup保障进程不会被hangup信号异常中断;
2) 将任务放置到后台运行,不占用当前的终端;
3) 将错误输出也打印到log中,默认>只有标准输出,错误输出没有。
3. jobs
使用格式:jobs [-lnprs] [jobspec ...] or jobs -x command [args]
jobs 用于查看当前进程,且只看当前终端生效的,关闭终端后在另一个终端jobs已经无法看到后台跑得程序了,那时需利用ps
控制进程(disown 中经常使用)
查看当前终端下的后台进程:
直接执行:jobs -l
切换到前台,将查看到的某个后台进程放回到前台:
直接输入:fg {jobid} // 这里的{jobid}是通过jobs命令中看到的进程前[]中的数字
切换到后台,将当前正在前台运行的进程放到后台运行:
先敲下快捷键:ctrl +z // 暂停当前正在运行的进程
再执行:bg
终止当前正在前台运行的进程:
直接敲下快捷键:ctrl +c
应用实例:
/usr/bin/Xvfb :7 -ac -screen 0 1280x1024x8 > /dev/null 2>&1 &
export DISPLAY=:7
nohup java -jar selenium-server-standalone-3.8.0.jar -port 8888 &
运行查看日志:
$ nohup java -jar selenium-server-standalone-3.8.0.jar -port 8888 & [1] 10020 $ nohup: ignoring input and appending output to ‘nohup.out’ $ $ ll -rw-r--r-- 1 homer homer 3730403 12月 24 23:18 chromedriver_linux64_v2.34.zip -rw-rw-r-- 1 homer homer 90 12月 26 22:26 composer.json -rw-rw-r-- 1 homer homer 41340 12月 26 22:31 composer.lock -rwxr-xr-x 1 homer homer 1855013 12月 26 22:25 composer.phar* -rw-rw-r-- 1 homer homer 2259579 1月 2 12:10 geckodriver-v0.19.0-linux64.tar.gz -rw-r--r-- 1 homer homer 2301226 12月 25 22:56 geckodriver-v0.19.1-linux64.tar.gz -rw------- 1 homer homer 22448 1月 2 16:52 nohup.out -rw-rw-r-- 1 homer homer 22844105 1月 2 11:53 selenium-server-standalone-3.8.0.jar -rw-rw-r-- 1 homer homer 22844868 12月 28 13:31 selenium-server-standalone-3.8.1.jar drwxrwxr-x 12 homer homer 4096 12月 26 22:31 vendor/ $ jobs -l [1]+ 10020 Running nohup java -jar selenium-server-standalone-3.8.0.jar -port 8888 &
日志可见,自动在当前目录下,创建了日志文件 nohup.out
关闭当前终端,然后再打开终端,查看 nohup 是否仍然在运行(没有被挂断)
$ ps -ef | grep java homer 10020 1 0 16:59 ? 00:00:04 java -jar selenium-server-standalone-3.8.0.jar -port 8888
确认了,nohup 和 & 配合使用,关闭终端后再重启终端,java 仍然一直在后台运行,没有被挂断
4. setsid
setsid - run a program in a new session
setsid 是让提交的命令归属一个新会话,即新开一个终端,其用法与nohup类似。
$ setsid java -jar selenium-server-standalone-3.8.0.jar -port 8888 & [2] 10269 $ 17:23:40.735 INFO - Selenium build info: version: '3.8.0', revision: '924c4067df'
不同的是 setsid 是新开一个终端会话,nohup是在当前的终端会话
例如:对比下进程父ID(PPID)
$ ps -ef | grep java homer 10020 9859 0 17:05 pts/1 00:00:02 java -jar selenium-server-standalone-3.8.0.jar -port 8888 homer 10270 1 22 17:23 ? 00:00:01 java -jar selenium-server-standalone-3.8.0.jar -port 8888 homer 10291 9859 0 17:23 pts/1 00:00:00 grep --color=auto java
通过对比可看出,使用setsid提交的命令父进程id为1,并不是当前终端进程id;而 nohup提交的命令父进程id为当前终端id=9859
5. disown
使用格式:disown [-h] [-ar] [jobspec ...]
如果未加任何处理就已经提交了命令,可使用disown补救,为没有使用nohup与setsid的进程加上忽略HUP信号的功能,例如提交的命令可用&放入后台运行
如果执行的命令想在前台和后台切换,也可以使用disown进行控制切换。
应用实例:
创建一个ping脚本进行运行模拟
vim mimvp-shell.sh
#!/bin/bash ping mimvp.com
一般后台运行
$ sh mimvp-shell.sh & [1] 12189 $ jobs -l [1]+ 12189 Running sh mimvp-shell.sh &
当前终端关闭后,此进程会随之关闭,终止
disown 后台运行
$ sh mimvp-shell.sh & [1] 12357 $ jobs -l [1]+ 12357 Running sh mimvp-shell.sh & $ $ disown -h %1 $ $ jobs -l [1]+ 12357 Running sh mimvp-shell.sh & $ $ ps -ef | grep mimvp homer 12357 12279 0 19:15 pts/24 00:00:00 sh mimvp-shell.sh homer 12358 12357 0 19:15 pts/24 00:00:00 ping mimvp.com homer 12385 12279 0 19:18 pts/24 00:00:00 grep --color=auto mimvp
如上,执行 disown -h %1 后,通过 jobs -l 查看进程号前后几乎没有变化,ps 查看进程号也几乎没有变化
接着,关闭终端,并重启终端后,通过 ps 查看进程 sh mimvp-shell.sh
$ ps -ef | grep mimvp homer 12357 1 0 19:15 ? 00:00:00 sh mimvp-shell.sh homer 12358 12357 0 19:15 ? 00:00:00 ping mimvp.com homer 12534 12498 0 19:22 pts/5 00:00:00 grep --color=auto mimvp
发现进程 sh mimvp-shell.sh 仍然在运行,且其父进程id=1
即执行 disown -h %1 命令后,让作业号为1的进程,转为了后台nohup进程,即成功实现了亡羊补牢
实现了功能: 后台命令 —> nohup 后台运行
disown 进一步的亡羊补牢
$ sh mimvp-shell.sh PING mimvp.com (47.95.6.112) 56(84) bytes of data. 64 bytes from 47.95.6.112: icmp_seq=1 ttl=53 time=8.87 ms 64 bytes from 47.95.6.112: icmp_seq=2 ttl=53 time=8.94 ms 64 bytes from 47.95.6.112: icmp_seq=3 ttl=53 time=11.9 ms ^Z (Ctrl + z 挂起前台进程) [1]+ Stopped sh mimvp-shell.sh $ bg 1 (bg 1 切换到后台进程; fg 切换到前台进程) [1]+ sh mimvp-shell.sh & $ 64 bytes from 47.95.6.112: icmp_seq=4 ttl=53 time=9.07 ms $ disown -h %1 $ jobs -l [1]+ 12800 Running sh mimvp-shell.sh &
说明:
1) 一开始在前台运行命令 sh mimvp-shell.sh
2) Ctrl + z 挂起前台进程
3) bg 1 (bg 1 切换到后台进程; fg 切换到前台进程)
4) disown -h %1 后台进程挂起
5) 关闭终端,重启终端后,仍然在后台执行
$ ps -ef | grep mimvp homer 12800 1 0 19:30 ? 00:00:00 sh mimvp-shell.sh homer 12801 12800 0 19:30 ? 00:00:00 ping mimvp.com homer 12971 12927 0 19:37 pts/24 00:00:00 grep --color=auto mimvp
实现了功能: 前台命令 —> 后台命令 —> nohup 后台运行
补充说明:
jobs -l 查看当前作业一般接-l,用于显示其作业号
bg %作业号,将作业在后台运行,例如 bg 1, bg %1
fg %作业号,将作业在前面处理,例如 fg 1, fg %1
CTRL-z,将当前程序挂起
6. screen
screen是建立一个新的全屏虚拟会话终端,这个会话只有在手动输入exit的时候才会退出,在这个会话里执行的命令不用担心HUP信号会对我们的进程造成影响,因此也不用给每个命令前都加上“nohup”或“setsid”了,非常适合我们有规划的执行大量的后台任务,可以非常方便的让我们对这些后台任务进行管理。
Ubuntu 安装命令:
sudo apt-get -y install screen
使用方法:Linux screen 命令详解
screen //立即创建并进入一个会话。
screen -dmS {name} //建立一个处于挂起模式下的会话,并根据我们的需要指定其会话名称。
screen -dmS {name} {script} //在建立会话时同时执行指定的命令或脚本
screen -list //列出所有会话。
screen -r {name} //以独占方式进入指定会话。
screen -x {name} //以并行方式进入指定会话。
ctrl +ad //输入快捷键ctrl +a和d,可暂时退出当前会话。
exit //进入指定会话后执行exit即可关闭该会话。
screen - screen manager with VT100/ANSI terminal emulation
Screen is a full-screen window manager that multiplexes a physical terminal between several processes (typically interactive shells). Each virtual terminal provides the functions of a DEC VT100 terminal and, in addition, several control functions from the ISO 6429 (ECMA 48, ANSI X3.64) and ISO 2022 standards (e.g. insert/delete line and support for multiple character sets). There is a scrollback history buffer for each virtual terminal and a copy-and-paste mechanism that allows moving text regions between windows.
$ screen --help Use: screen [-opts] [cmd [args]] or: screen -r [host.tty] Options: -4 Resolve hostnames only to IPv4 addresses. -6 Resolve hostnames only to IPv6 addresses. -a Force all capabilities into each window's termcap. -A -[r|R] Adapt all windows to the new display width & height. -c file Read configuration file instead of '.screenrc'. -d (-r) Detach the elsewhere running screen (and reattach here). -dmS name Start as daemon: Screen session in detached mode. -D (-r) Detach and logout remote (and reattach here). -D -RR Do whatever is needed to get a screen session. -e xy Change command characters. -f Flow control on, -fn = off, -fa = auto. -h lines Set the size of the scrollback history buffer. -i Interrupt output sooner when flow control is on. -l Login mode on (update /var/run/utmp), -ln = off. -ls [match] or -list. Do nothing, just list our SockDir [on possible matches]. -L Turn on output logging. -m ignore $STY variable, do create a new screen session. -O Choose optimal output rather than exact vt100 emulation. -p window Preselect the named window if it exists. -q Quiet startup. Exits with non-zero return code if unsuccessful. -r [session] Reattach to a detached screen process. -R Reattach if possible, otherwise start a new session. -s shell Shell to execute rather than $SHELL. -S sockname Name this session <pid>.sockname instead of <pid>.<tty>.<host>. -t title Set title. (window's name). -T term Use term as $TERM for windows, rather than "screen". -U Tell screen to use UTF-8 encoding. -v Print "Screen version 4.01.00devel (GNU) 2-May-06". -wipe [match] Do nothing, just clean up SockDir [on possible matches]. -x Attach to a not detached screen. (Multi display mode). -X Execute <cmd> as a screen command in the specified session.
参考推荐:
Difference between nohup, disown and &
PHP + Selenium + WebDriver 抓取米扑科技首页
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2018-05-26 05:37:16
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!