从脚本启动后台进程,并在脚本结束时进行管理


15

我想要类似于脚本中的守护程序来运行和配置进程。
我的Shell是在Cygwin下模拟的zsh,守护进程是基本的FTP服务器SFK

对于这里重要的事情,脚本startserv.sh可以按如下方式草拟:

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
$cmd &

运行脚本后startserv.sh,它停止(结束?)而不显示任何提示,然后:

  • CTRL+ C结束脚本和后台作业过程;

  • 点击Enter脚本将结束该过程,并保留在后台。

无论如何,我只能通过ps而看不到它jobs,因此,当我想关闭该过程时,我必须发送一个残酷的kill -9信号,我希望避免使用 CTRL+ C

另一种方法 在后台运行整个脚本。“将”,但是read如果脚本以方式运行,则该命令将无法获取用户输入startserv.sh &

请注意,我需要一个临时服务器,而不是真正的守护程序:也就是说,我希望服务器进程在脚本结束后在后台运行,以执行简单的交互式Shell任务(使用虚拟机来宾),但是我不希望这样做。不需要生存过程的壳;因此nohup似乎不合适。


使用来获取在后台运行的进程的进程ID,bgproc="$!"然后command "$bgproc" 采取适当的措施。另请参见stackoverflow.com/questions/1908610/...
瓦伦丁巴伊拉米

您还可以制作一个PID文件。然后阅读该文件以查看它是什么进程号,然后从那里开始。
2014年

Answers:


18

点击Enter脚本将结束该过程,并保留在后台。

几乎!实际上,按时该脚本已退出Enter。但是,这是您可以找回提示的方法(因为您的shell会重新打印$PS1一次)。

点击Ctrl+ C终止它们两个的原因是因为它们两个是链接的。当您执行脚本时,您的外壳会启动一个子外壳以在其中运行它。终止此子Shell时,后台进程可能会死于SIGHUP信号。

分离脚本,后台进程和子外壳

使用nohup,您可以摆脱这种不便之处。

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
nohup $cmd &

disown替代

如果可以从切换/bin/sh/bin/bash,也可以尝试disown。要了解更多信息,只需输入help disown一个bash实例。

disown -h $cmd &

巧妙地杀死后台进程

现在,当涉及到终止进程时,您可以使用完美地执行“ Ctrl+ Ckill。只是不要发送野蛮的东西SIGKILL。相反,您可以使用:

$ kill -2 [PID]
$ kill -15 [PID]

它将为您的过程发送一个不错的SIGINT(2)或SIGTERM(15)。您可能还希望在开始该过程后打印PID值:

...
nohup $cmd &
echo $!

...甚至更好,让脚本等待SIGINT,然后将其发送回后台进程(尽管这样会使脚本保持在前台)

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
nohup $cmd &

# Storing the background process' PID.
bg_pid=$!

# Trapping SIGINTs so we can send them back to $bg_pid.
trap "kill -2 $bg_pid" 2

# In the meantime, wait for $bg_pid to end.
wait $bg_pid

如果a SIGINT还不够,请SIGTERM改用(15):

trap "kill -15 $bg_pid" 2 15

这样,当您的脚本在后台进程中收到一个SIGINTCtrl+ Ckill -2)或SIGTERM一会儿时wait,它只会将信号中继给它。如果这些信号确实杀死了sfk实例,则wait调用将返回,因此也终止了脚本:)


1
+1非常有用。由于脚本在子外壳程序中运行,是否有可能从脚本访问脚本的父外壳程序的作业表?也就是说jobs,脚本结束后(而不是ps)在终端中发布列表作业。
2014年

1
作业与您当前的外壳相关联,它们不会从一个外壳传输到另一个外壳。当您的子外壳死亡时,其工作将无法恢复。通过打印后台进程的PID,即使在子Shell终止后,也确保可以轻松获得有关它的信息pid -p
约翰·史密斯

很好的解释,但是,如果您的脚本包含更多命令,则它们将永远不会执行(由于wait)。如果您删除等待,则信号处理将中断:/
Chefarov
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.