需求
网络上有一些很好的课程合集,然而受到版权限制,有时候会被封禁,于是最好的办法就是自己下载下来。
这里采用 you-get 在服务器上挂载下载(相当于离线下载)。
问题
使用 ssh 连接上服务器之后就可以下载了,然而每次断开 ssh 连接之后,下载会自动停止,为什么?
答:当用户注销(logout)或者网络断开时,终端会收到 HUP(hangup)信号从而关闭其所有子进程。
因此,我们的解决办法就有两种途径:要么让进程忽略 HUP 信号,要么让进程运行在新的会话里从而成为不属于此终端的子进程。
解决:nohup/setsid/&
nohup you-get https://www.bilibili.com/video/av52118083 --playlist &
# [1] 21999
# nohup: ignoring input and appending output to 'nohup.out'
jobs
# [1]+ Running nohup you-get https://www.bilibili.com/video/av52118083 --playlist &
只需在要处理的命令前加上 nohup 即可,标准输出和标准错误缺省会被重定向到 nohup.out 文件中。一般我们可在结尾加上"&"来将命令同时放入后台运行。
# 1
nohup - run a command immune to hangups, with output to a non-tty
SYNOPSIS
nohup COMMAND [ARG]...
nohup OPTION
DESCRIPTION
Run COMMAND, ignoring hangup signals.
# 2
setsid - run a program in a new session
SYNOPSIS
setsid program [ arg ... ]
DESCRIPTION
setsid runs a program in a new session.
总结
# 方式一: nohup,忽略 hungup 信号
nohup ping www.ibm.com &
# 方式二:运行在新会话中,父 ID(PPID)为1(即为 init 进程 ID),并不是当前终端的进程 ID
setsid ping www.ibm.com
# 方式二
(ping www.ibm.com &) # 将一个或多个命名包含在“()”中就能让这些命令在子 shell 中运行中,加上 & 之后,新提交的进程的父 ID(PPID)为1(init 进程的 PID),并不是当前终端的进程 ID
补救?
我们已经知道,如果事先在命令前加上 nohup 或者 setsid 就可以避免 HUP 信号的影响。但是如果我们未加任何处理就已经提交了命令,该如何补救才能让它避免 HUP 信号的影响呢?
只能通过作业调度和 disown 来解决这个问题了。
disown [-ar] [-h] [jobspec ...]
Without options, each jobspec is removed from the table of
active jobs. If the -h option is given, each jobspec is not
removed from the table, but is marked so that SIGHUP is not
sent to the job if the shell receives a SIGHUP. If no jobspec
is present, and neither the -a nor the -r option is supplied,
the current job is used. If no jobspec is supplied, the -a
option means to remove or mark all jobs; the -r option without
a jobspec argument restricts operation to running jobs. The
return value is 0 unless a jobspec does not specify a valid
job.
- 用
disown -h jobspec来使某个作业忽略HUP信号。 - 用
disown -ah来使所有的作业都忽略HUP信号。 - 用
disown -rh来使正在运行的作业忽略HUP信号。
需要注意的是,当使用过 disown 之后,会将把目标作业从作业列表中移除,我们将不能再使用jobs来查看它,但是依然能够用ps -ef查找到它。
但是还有一个问题,这种方法的操作对象是作业,如果我们在运行命令时在结尾加了"&"来使它成为一个作业并在后台运行,那么就万事大吉了,我们可以通过jobs命令来得到所有作业的列表。但是如果并没有把当前命令作为作业来运行,如何才能得到它的作业号呢?答案就是用 CTRL-z(按住Ctrl键的同时按住z键)了!
CTRL-z 的用途就是将当前进程挂起(Suspend),然后我们就可以用jobs命令来查询它的作业号,再用bg jobspec来将它放入后台并继续运行。需要注意的是,如果挂起会影响当前进程的运行结果,请慎用此方法。
拓展阅读/参考
dfface 的版权声明:所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处,严禁商业用途!