本文目录导读:

- 通用 Shell 脚本 (适用于 Java、Python 等后台进程)
- 针对 Java 程序 (Systemd 风格 - 推荐生产环境)
- 针对 Python 程序 (使用 Gunicorn/Uvicorn)
- 针对 Go / C / C++ 编译的二进制程序
- Windows 批处理脚本 .bat
- 总结最佳实践
这里为您整理了几种常见环境下(Java、Python、通用服务)的启动停止脚本示例,并加入了最佳实践(如PID文件、检测进程、优雅关闭)。
通用 Shell 脚本 (适用于 Java、Python 等后台进程)
这是最经典的模板,使用 PID 文件来管理进程。
#!/bin/bash
# description: 通用服务启动/停止脚本
# usage: ./service.sh {start|stop|restart|status}
# 请修改以下变量为您的服务名和启动命令
APP_NAME="my_app"
APP_HOME="/path/to/your/app"
EXECUTABLE="java -jar $APP_HOME/app.jar"
PID_FILE="$APP_HOME/$APP_NAME.pid"
LOG_FILE="$APP_HOME/$APP_NAME.log"
# 获取当前进程 PID
get_pid() {
if [ -f "$PID_FILE" ]; then
cat "$PID_FILE"
else
echo ""
fi
}
# 检查进程是否在运行
is_running() {
local pid=$(get_pid)
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
return 0 # true
else
return 1 # false
fi
}
# 启动服务
start() {
if is_running; then
echo "$APP_NAME 已经在运行中 (PID: $(get_pid))"
exit 1
fi
echo "正在启动 $APP_NAME ..."
# 使用 nohup 在后台运行,并输出日志
nohup $EXECUTABLE > "$LOG_FILE" 2>&1 &
local new_pid=$!
echo $new_pid > "$PID_FILE"
sleep 1
if is_running; then
echo "$APP_NAME 启动成功 (PID: $new_pid)"
else
echo "$APP_NAME 启动失败,请检查日志: $LOG_FILE"
exit 1
fi
}
# 停止服务
stop() {
if ! is_running; then
echo "$APP_NAME 未在运行"
return 0
fi
local pid=$(get_pid)
echo "正在停止 $APP_NAME (PID: $pid) ..."
# 1. 尝试优雅关闭 (SIGTERM)
kill "$pid" 2>/dev/null
# 2. 等待进程结束(最多等待 30 秒)
local wait_count=0
while is_running && [ $wait_count -lt 30 ]; do
sleep 1
((wait_count++))
done
# 3. 如果还在运行,强制杀掉 (SIGKILL)
if is_running; then
echo "进程未能优雅停止,强制执行 kill -9 ..."
kill -9 "$pid" 2>/dev/null
sleep 1
fi
# 4. 删除 PID 文件
rm -f "$PID_FILE"
echo "$APP_NAME 已停止"
}
# 重启服务
restart() {
stop
sleep 2 # 等待端口释放
start
}
# 查看状态
status() {
if is_running; then
echo "$APP_NAME 正在运行 (PID: $(get_pid))"
else
echo "$APP_NAME 未在运行"
fi
}
# 主入口
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
status)
status
;;
*)
echo "用法: $0 {start|stop|restart|status}"
exit 1
;;
esac
针对 Java 程序 (Systemd 风格 - 推荐生产环境)
对于 CentOS 7+ / Ubuntu 16+,使用 systemd 是最现代化的方式。
文件路径: /etc/systemd/system/myapp.service
[Unit] Description=My Java Application Service After=network.target [Service] Type=simple User=appuser WorkingDirectory=/opt/myapp ExecStart=/usr/bin/java -Xms256m -Xmx1024m -jar /opt/myapp/app.jar ExecStop=/bin/kill -s TERM $MAINPID SuccessExitStatus=143 Restart=always RestartSec=10 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target
使用方法:
# 重新加载配置 sudo systemctl daemon-reload # 启动 sudo systemctl start myapp # 停止 sudo systemctl stop myapp # 重启 sudo systemctl restart myapp # 查看状态 sudo systemctl status myapp # 设置为开机自启 sudo systemctl enable myapp
针对 Python 程序 (使用 Gunicorn/Uvicorn)
对于 Web 应用 (Flask/Django/FastAPI) 经常配合 Gunicorn。
文件路径: /etc/init.d/my-python-app 或作为 systemd 服务。
#!/bin/bash
# chkconfig: 2345 80 20
# description: Python Web Service
APP_NAME="webapp"
APP_PATH="/opt/myapp"
VENV_PATH="$APP_PATH/venv/bin/activate"
GUNICORN="$APP_PATH/venv/bin/gunicorn"
PID_FILE="/var/run/$APP_NAME.pid"
start() {
echo "Starting $APP_NAME ..."
cd $APP_PATH
source $VENV_PATH
$GUNICORN --workers 3 --bind 0.0.0.0:8000 wsgi:app \
--pid $PID_FILE \
--daemon \
--access-logfile /var/log/$APP_NAME/access.log \
--error-logfile /var/log/$APP_NAME/error.log
echo "$APP_NAME started."
}
stop() {
echo "Stopping $APP_NAME ..."
if [ -f $PID_FILE ]; then
kill -TERM $(cat $PID_FILE) 2>/dev/null
rm -f $PID_FILE
fi
echo "$APP_NAME stopped."
}
case "$1" in
start) start ;;
stop) stop ;;
restart) stop; sleep 2; start ;;
*) echo "Usage: $0 {start|stop|restart}" ;;
esac
针对 Go / C / C++ 编译的二进制程序
Go 或 C 程序通常是单文件二进制,启动简单。
#!/bin/bash
APP="/usr/local/bin/my-server"
APP_NAME="myserver"
PID_FILE="/var/run/${APP_NAME}.pid"
start() {
if [ -f $PID_FILE ] && kill -0 $(cat $PID_FILE) 2>/dev/null; then
echo "$APP_NAME already running."
exit 1
fi
echo "Starting $APP_NAME..."
$APP &>/dev/null &
echo $! > $PID_FILE
echo "$APP_NAME started."
}
stop() {
if [ ! -f $PID_FILE ]; then
echo "$APP_NAME not running."
exit 1
fi
echo "Stopping $APP_NAME..."
kill $(cat $PID_FILE) 2>/dev/null
rm -f $PID_FILE
echo "$APP_NAME stopped."
}
case "$1" in
start|stop|restart) $1 ;;
*) echo "Usage: $0 {start|stop|restart}" ;;
esac
Windows 批处理脚本 .bat
@echo off
set APP_NAME=MyApp
set JAR_PATH=C:\myapp\app.jar
set PID_FILE=%TEMP%\%APP_NAME%.pid
if "%1"=="start" goto start
if "%1"=="stop" goto stop
if "%1"=="restart" goto restart
echo Usage: %0 {start^|stop^|restart}
goto :eof
:start
echo Starting %APP_NAME% ...
start "%~n0" javaw -jar %JAR_PATH%
echo %ERRORLEVEL% > %PID_FILE%
echo %APP_NAME% started.
goto :eof
:stop
echo Stopping %APP_NAME% ...
taskkill /f /fi "PID eq %PID_FILE%" 2>nul
del %PID_FILE% 2>nul
echo %APP_NAME% stopped.
goto :eof
:restart
call :stop
timeout /t 2 /nobreak >nul
call :start
goto :eof
总结最佳实践
| 特性 | 说明 |
|---|---|
| PID 文件 | 用于存储进程ID,方便查找和杀死 |
| SIGTERM vs SIGKILL | 先发 TERM (15) 优雅关闭,等几秒再发 KILL (9) 强制 |
| 日志重定向 | nohup + 2>&1 将输出写入文件 |
| 状态检查 | kill -0 PID 检查进程是否存在 |
| Systemd | 生产环境推荐,自带PID、自动重启、资源限制 |
您可以根据自己的服务类型选择对应的脚本模板,如果您有具体的服务(比如是 Spring Boot、Flask、Node.js),我可以帮您定制更精确的版本。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播