练习编写一个MineCreaft 系统服务启动脚本,这样我不仅仅可以方便的使用
service
启动MC服务器,又可以练习shell编程,一举两得
MineCraft
服务器启动脚本
大致思路
一般启动服务器的时候,我们通过screen
来启动mc服务器,这样有一个好处是,有了screen开创的窗口,我们随时可以进入它去控制服务器,那么我希望 启动脚本,启动的时候 创建一个screen ,在这里面开启服务器。控制关闭等其他操作,向刚才的创建好的screen输出命令即可。
编写的时候我遇到了一些不大不小的问题,如下
- service 编写的规则
- 如何使用
screen
启动mc服务器 - 如何screen 后台键入命令
- 如何判断服务是否启动
好在MineCraft WIKI百科上有启动脚本案例,其实以及完美的解决我的需求!ahh,既然如此,我就学习wiki百科上的案例!
参考链接:
service 服务shell脚本案例
Service 日常使用规则如下:可通过 service [serviceNAME] start|stop|status|restart 命令对服务进行控制
, 这里有一个 httpd(apache),启动脚本的案例,我们可以研究一下:
#!bin/bash
#chkconfig:2345 55 25 //运行级别、启动优先级、关闭优先级
#processname:httpd //进程名
#description:source httpd server daemon //服务描述
prog=/usr/local/httpd/bin/apachectl //控制程序路径
lock=/usr/local/httpd/httpd.lock //lock文件路径
start(){ //start函数
$prog start
echo "正在启动服务...."
touch $lock
}
stop(){ //stop函数
$prog stop
echo "正在停止服务...."
rm -rf $lock
}
status(){ //status函数
if [ -e $lock ];then
echo "$0 服务正在运行"
else
echo "$0 服务已经停止"
fi
}
restart(){ //restart函数
stop
start //直接调用stop、start函数,
}
case "$1" in //case分支结构匹配,$1位置参数对控制参数调用
"start")
start //调用start函数
;;
"stop") //调用stop函数
stop
;;
"status") //调用status函数
status
;;
"restart") //调用restart函数
restart
;;
*) //其他参数就输出脚本正确用法
echo "用法:$0 start|stop|status|restart"
;;
esac
如果你掌握了不错的shell基础,相信这些代码都难不倒你,编写service 服务shell脚本,其实就是使用 case语句进行控制,当然为了代码的整洁,通常将一个功能封装成一个函数 ,case根据不同的 $1
(位置参数)
如何判断服务是否启动
判断服务是否启动,我们使用 pgrep
命令 ,通过pgrep来获得正在被调度的进程的相关信息。pgrep通过匹配其程序名,找到匹配的进程。我们启动minecratf
服务器不希望使用root用户,这不是一个很安全的方式,所以我们可以封装一个函数,执行命令的时候 使用没有那么大权限的用户,为此,可以封装一个函数 as_user()
ME=`whoami`
#确保是 设定用户执行脚本
as_user()
{
if [ $ME = $USERNAME ]
then
bash -c "$1"
else
su - "$USERNAME" -c "$1"
fi
}
需要执行的命令使用 $1
传入。说回 pgrep
使用 ,这里用法为 pgrep -u [username] -f [process]
这样会返回 进程pid ,感觉集成了 ps | grep
两种命令的组合命令。
if pgrep -u $USERNAME -f $SERVICE > /dev/null ; then
# 服务以及启动
else
# 服务没有启动
fi
> /dev/null
就是为了不让改命令的输出 出现在屏幕上
screen的使用
后台执行命令
screen后台执行命令的案例如下 screen -dmS test bash -c 'ping www.baidu.com';
,使用 -dmS
参数开启一个已断开的会话,可以绕过手动断开操作. 你想后台调用的命令 可以直接使用 bash -c
执行,当然如果执行的命令中有参数的话,需要使用 eval
将命令扫描两次再去执行,第一次将变量值提取出来,第二次 执行命令。
后台键入命令
使用语法格式为 screen -S $screen_name -p 0 -X stuff "$cmd"
,原理应当是发送命令至指定会话中执行,所以前期创建会话时,应指定会话名。参数 -S 指定会话 参数 -X 发送命令 参数 stuff ?疑似?是输出命令执行 参数 -p 指定屏幕。
到这里,基本难题都解决了。 当然我们给mc后台输入命令,还需要 多输入一个 \r
才可以执行哦
code
其实就是 官方案例的摘抄,学习别人的代码也是一种进步(编程就是 ctrl+c ctrl+v)
#! /bin/bash
# /etc/init.d/minecraft
# info start
# Minecraft 服务器启动脚本
# 作者: 越行勤
# 版本 0.1
# 环境需要 CentsOs8 需要安装 screen tar java 等必要工具和环境
# info end
#Settings
SERVICE="spigot-1.17.jar"
SERVICENAME="MineCraft_spigot_1.17_SERVICE"
USERNAME="minecraft"
MCPATH="/home/minecraft/minecraft1.17"
BACKUPPATH="/home/minecraft/backup"
SCREENNAME=mc
MAXHEAP=2048
MINHEAP=1024
INVOCATION="java -Xms${MINHEAP}m -Xmx${MAXHEAP}m -jar $SERVICE nogui"
ME=`whoami`
#确保是 设定用户执行脚本
as_user()
{
if [ $ME = $USERNAME ]
then
bash -c "$1"
else
su - "$USERNAME" -c "$1"
fi
}
# 启动mc
mc_start()
{
if pgrep -u $USERNAME -f $SERVICE > /dev/null ; then
echo "$SERVICENAME is already running!"
else
echo "Strating $SERVICENAME ..."
cd $MCPATH
# 登录USRNAME用户 创建screen 启动服务器
as_user "cd $MCPATH && screen -h $HISTORY -dmS ${SCREENNAME} bash -c '${INVOCATION}'"
sleep 7
# 7s后如果mc服务器还没启动 那么启动失败
pgrep -u $USERNAME -f $SERVICE
if [ $? = 0 ]
then
echo "$SERVICE is now running."
else
echo "Error! Could not start $SERVICE!"
fi
fi
}
mc_saveoff()
{
if pgrep -u $USERNAME -f $SERVICE > /dev/null ; then
echo "$SERVICENAME is running ... suspending saves"
as_user "screen -S ${SCREENNAME} -p 0 -X eval 'stuff \"say SERVER BACKUP STARTING. Server going readonly...\"\r'"
as_user "screen -S ${SCREENNAME} -p 0 -X eval 'stuff \"save-off\"\r'"
as_user "screen -S ${SCREENNAME} -p 0 -X eval 'stuff \"save-all\"\r'"
sync
sleep 10
else
echo "$SERVICE is not running. Not suspending saves."
fi
}
mc_saveon()
{
if pgrep -u $USERNAME -f $SERVICE > /dev/null ; then
echo "$SERVICENAME is running ... re-enable saves"
as_user "screen -S ${SCREENNAME} -p 0 -X eval 'stuff \"save-on\"\r'"
as_user "screen -S ${SCREENNAME} -p 0 -X eval 'stuff \"say Server BackUp Ended! Server going read-write...\"\r'"
sleep 10
else
echo "$SERVICE is not running. Not suspending saves."
fi
}
mc_stop()
{
if pgrep -u $USERNAME -f $SERVICE > /dev/null ; then
echo "stoping $SERVICENAME "
as_user "screen -S ${SCREENNAME} -p 0 -X eval 'stuff \"say SERVER SHUTDOWN IN ten SECONDS . SAVING MAP\"\r'"
as_user "screen -S ${SCREENNAME} -p 0 -X eval 'stuff \"save-all\"\r'"
for i in {10..1}
do
as_user "screen -S ${SCREENNAME} -p 0 -X eval 'stuff \"say $i s..\"\r'"
sleep 1
done
as_user "screen -S ${SCREENNAME} -p 0 -X eval 'stuff \"stop\"\r'"
sleep 7
else
echo "$SERVICE was not running."
fi
if pgrep -u $USERNAME -f $SERVICE > /dev/null
then
echo "Error! $SERVICE could not be stopped."
else
echo "$SERVICE is stopped."
fi
}
mc_backup()
{
# 根据需求更改
}
#Start-Stop here
case "$1" in
start)
mc_start
;;
stop)
mc_stop
;;
restart)
mc_stop
mc_start
;;
status)
if pgrep -u $USERNAME -f $SERVICE > /dev/null
then
echo "$SERVICE is running."
else
echo "$SERVICE is not running."
fi
;;
*)
echo "Usage: $0 {start|stop|update|backup|status|restart|command \"server command\"}"
exit 1
;;
esac
exit 0