【问题标题】:How can I improve this bash script?如何改进这个 bash 脚本?
【发布时间】:2018-05-09 13:36:23
【问题描述】:

我正在尝试编写一个 bash 脚本。 该脚本应检查 MC 服务器是否正在运行。如果它崩溃或停止,它将自动启动服务器。

我将使用 crontab 每分钟运行一次脚本。我想我可以每秒运行一次它不会对 CPU 造成太大压力。我也想知道服务器什么时候重启。所以我要把日期打印到“RestartLog”文件中。

这是我目前所拥有的:

   #!/bin/sh

ps auxw | grep start.sh | grep -v grep > /dev/null

if [ $? != 0 ]
then
        cd /home/minecraft/minecraft/ && ./start.sh && echo "Server restarted on: $(date)" >> /home/minecraft/minecraft/RestartLog.txt > /dev/null
fi

我刚开始学习 Bash,我不确定这是否是正确的方法。

【问题讨论】:

  • 试图避免这种被封闭为固执己见,“你会怎么做”和“这是正确的方式”是边缘固执己见,因为我们都会以不同的方式做这件事。最好帮助您编写代码和样式。那么你的代码有效吗?它具体没有做什么你想要的?
  • 我强烈建议您将其写为:if ! ps ....; then ...; fi。不要明确检查$?;几乎从不需要,如果您直接检查命令状态,脚本会更干净。
  • 第二个建议是;不要这样做。与其从 cron 生成一个(非常脆弱的)检查您的服务器是否正在运行的作业,不如在 systemd 或 supervisord 的监督下运行服务器。
  • $? 是一个整数,应该在[ … ] 中这样对待,这意味着你应该使用[ $? -ne 0 ]。请参阅man test,因为[ 实际上只是名为test 的程序的别名。
  • 您的 echo-log 命令定义了 2 个输出重定向,这是一个错误:第一个是 >> …/RestartLog.txt,第二个是 > /dev/null。因为一个程序只有一个标准输出,所以只有一个重定向可以生效。 shell 实际上会轮流应用这两个,但只有最后一个获胜,所以日志消息被发送到/dev/null。您可能希望第二个输出重定向将标准错误重定向到/dev/null,这将被写为2> /dev/null,但这实际上是没有用的,因为echo 永远不会在标准错误上产生任何输出(除非魔法)。

标签: bash


【解决方案1】:

使用 cron 是可能的,还有其他(更好的)解决方案(monit、supervisord 等)。但这不是问题;您要求“正确的方式”。正确的方法很难定义,但了解代码中的限制和问题可能会对您有所帮助。

以正常的cron 执行最多每分钟发生一次。这意味着您的 minecraft 服务器可能会在重新启动前 59 秒关闭。

   #!/bin/sh

你应该在行首有#!。不知道这是否是剪切/粘贴问题,但这很重要。此外,您可能希望使用 #!/bin/bash 而不是 #!/bin/sh 来实际使用 bash。

ps auxw | grep start.sh | grep -v grep > /dev/null

有些人可能会建议使用ps -ef,但这是一个品味问题。您甚至可以使用ps -ef | grep [s]tart.sh 来防止使用第二个grep。然而,这一行的主要问题是您正在解析进程列表以获得相当通用的start.sh。如果您有专门的服务器,这可能没问题,但如果服务器上有更多用户,您将面临其他人为完全不同的事情运行start.sh 的风险。

if [ $? != 0 ]
then

关于$?的使用和干净的代码已经有评论了。

    cd /home/minecraft/minecraft/ && ./start.sh && echo "Server restarted on: $(date)" >> /home/minecraft/minecraft/RestartLog.txt > /dev/null

保留重启日志是个好主意。在这一行中,您使./start.sh 的执行取决于cd 成功的事实。此外,只有在./start.sh 存在之后才会执行回显。

所以这给我留下了一个问题:只要服务器运行,start.sh 是否会继续运行(在这种情况下:ps-test 可以,但&& echo 没有意义,或者@ 987654340@ 退出,同时将 minecraft-server 留在后台(在这种情况下,ps-grep 将无法正常工作,但只有在start.sh 正确退出时才回显日志记录)。

fi

(fi不备注)

【讨论】:

  • 他使用grep -v。如果输出包含不包含“grep”的行,这将仅返回 0。所以if 部分应该是个问题。检查它echo grep|grep -v grep ;echo $? 给出1echo -e "grep\nsomething else"|grep -v grep ;echo $? 给出0
  • 你是绝对正确的。我的错。我删除了关于grep -v的评论。
【解决方案2】:

如果start.sh 阻塞直到服务器存在/崩溃,您最好在不涉及cron 的情况下简单地以无限循环重新启动它。只需在控制台中输入(或放入另一个脚本):

#!/bin/bash
cd /home/minecraft/minecraft/
while sleep 3; do
  echo "$(date) server (re)start" >> restart.log
  ./start.sh # blocks until server crashes
done

但如果它没有阻塞(即如果start.sh 启动服务器然后返回,但服务器继续运行),则需要执行不同的检查以验证服务器是否实际上仍在运行,除了ps|grep start.sh

PS:要终止无限循环,您必须两次Ctrl+C:一次停止./start.sh,一次退出立即sleep

【讨论】:

  • 感谢您的回答。我正在屏幕中运行服务器。屏幕名称是“我的世界”。因此,每当服务器崩溃时,它都会在现有的“我的世界”屏幕中启动。可能这是不多次启动服务器的最安全方法。
【解决方案3】:

您可以使用monit 执行此任务。 See docu。它在大多数 linux 发行版上都可用,并且具有简单的配置。找一些examples in this post

对于您的应用,它看起来像

check process minecraftserver
    matching "start.sh"
    start program = "/home/minecraft/minecraft/start.sh"
    stop program = "/home/minecraft/minecraft/stop.sh"

我写这个答案是因为有时最有效的解决方案已经存在,您无需编写任何代码。同时遵循William Pursell 的建议,使用您操作系统的初始化系统(systemd、upstart、system-v 等)来托管您的脚本。

了解更多: Shell Script For Process Monitoring

【讨论】:

  • 我没有否决您的回答。那是别人。我很感激你的回答!我会检查监视器。
  • 现在您添加的不仅仅是链接,我已经删除了反对票。仅链接的答案有点毫无意义;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-13
  • 1970-01-01
相关资源
最近更新 更多