我正在尝试改进集群环境中运行的几个服务器的启动脚本。服务器进程应该无限期运行,但在启动时偶尔会出现故障,例如Address already in use异常。我想启动脚本的退出代码来反映这些早期的终止,比如说,等待1秒,告诉我服务器是否已经启动了。我还需要回显服务器PID。这是我迄今为止最好的一张照片:$ cat startup.sh# start the server in the bg but if it fails in the first second,# then kill startup.sh.CMD="start_server -option1 foo -option2 bar"eval "($CMD >> cc.log 2>&1 || kill -9 $$ &)"SERVER_PID=$!# the `kill` above only has 1 second to kill me-- otherwise my exit code is 0sleep 1echo $SERVER_PID退出代码运行良好,但仍存在两个问题:如果服务器长时间运行,但最终遇到错误,则父将已经退出,并且startup.sh PID可能被一个无关的进程重用,该脚本随后将被销毁。$$不正确,因为它是子shell的pid,而不是SERVER_PID命令(在本例中是start_server脚本的孙子)。有没有一种更简单的方法来设置startup.sh进程的后台,获取其pid,并对错误代码使用超时检查?我研究了BASH构建体start_server和wait,但是它们对于不应该退出的进程似乎不起作用。我无法更改服务器代码,启动脚本不应无限期运行。 (adsbygoogle = window.adsbygoogle || []).push({}); 最佳答案 您也可以使用coproc(看,我将命令放入一个数组中,并且还使用适当的引号!)以下内容:#!/bin/bashcmd=( start_server -option1 foo -option2 bar )coproc mycoprocfd { "${cmd[@]}" >> cc.log 2>&1 ; }server_pid=$!sleep 1if [[ -z "${mycoprocfd[@]}" ]]; then echo >&2 "Failure detected when starting server! Server died before 1 second." exit 1else echo $server_pidfi诀窍在于coproc将STDIN和STDUT重定向的文件描述符放在指定的数组(这里是MeCuPROFD),并在进程退出时清空数组。所以你不需要用PID本身做笨拙的事情。因此,您可以检查服务器是否永远退出:#!/bin/bashcmd=( start_server -option1 foo -option2 bar )coproc mycoprocfd { "${cmd[@]}" >> cc.log 2>&1 ; }server_pid=$!read -u "${mycoprocfd[0]}"echo >&2 "Oh dear, the server with PID $server_pid died after $SECONDS seconds."exit 1这是因为read将读取coproc给定的文件描述符(但这里永远不会读取任何内容,因为您的命令的stdout已重定向到文件!)并在文件描述符关闭时读取退出,即当由coproc启动的命令退出时。我认为这是一个非常优雅的解决方案!现在,这个脚本将和coproc一样长寿。我知道这不是你想要的。在这种情况下,您可以使用其-t选项超时读取,然后使用返回的退出状态大于128的事实,如果它超时。例如,超时4.5秒#!/bin/bashtimeout=4.5cmd=( start_server -option1 foo -option2 bar )coproc mycoprocfd { "${cmd[@]}" >> cc.log 2>&1 ; }server_pid=$!read -t $timeout -u "${mycoprocfd[0]}"if (($?>128)); then echo "$server_pid <-- all is good, it's still alive after $timeout seconds."else echo >&2 "Oh dear, the server with PID $server_pid died after $timeout seconds." exit 1fiexit 0 # Yay这也是非常优雅的:)。使用、扩展和适应您的需求!(但要有良好的实践!)希望这有帮助!评论。coproc是bash 4.0中出现的bash内置。这里显示的解决方案是100%纯bash(除了第一个,带sleep,这不是最好的!)是的。在脚本中使用coproc几乎总是优于将作业放在&的背景中,以及在睡眠和检查$!时做笨拙和笨拙的事情。如果您希望coproc保持安静,无论发生什么(例如,如果启动命令时出错,这在这里很好,因为您自己处理所有事情),请执行以下操作:coproc mycoprocfd { "${cmd[@]}" >> cc.log 2>&1 ; } > /dev/null 2>&1 (adsbygoogle = window.adsbygoogle || []).push({}); 10-02 04:24