bat怎么写脚本(编写BAT脚本管理进程)
最近在Windows上搭建了个PHP MySQL nginx的开发环境,但是发现除了mysql可以注册成服务启动外,PHP和Nginx都无法注册成为服务,这样一来管理管理进程的启动和关闭就成了一件麻烦的事情,于是就想着写一个脚本来管理PHP和Nginx进程的启动和关闭,首先这个脚本接收两个参数:服务名和指令,用于指定管理的进程名称,可以对进程进行启动、关闭、重启等操作
通过脚本启动进程在批处理脚本中可以通过 start 命令来启动一个进程,下面以启动nginx为例,新建一个脚本文件 PhpTools.bat ,并写入如下内容
:: 关闭命令显示
@echo off
:: 需要确认已经将nginx进程加入到系统环境变量中,否则会出现找不到进程的错误,如果不想加入到环境变量,则可以指定完整的程序路径如:start /b nginx.exe
:: /b 参数指定以后台进程方式来运行程序
start /b nginx
尝试运行脚本查看结果,得到了一个错误,从错误信息中可以看出似乎是找不到配置文件的问题
通过排查发现,nginx在运行时默认以当前执行进程的目录为运行时目录,但是因为当前目录中并没有运行时所需要的必要文件环境,所以出现了上面的错误,在nginx中可以通过 -p 参数来指定运行时的主目录
编辑脚本文件,指定nginx运行时的主目录
:: 关闭命令显示
@echo off
...
- start /b nginx
start /b nginx -p D:\Apps\Nginx-1.21.1
再次执行脚本,可以看到这次没有出现错误了,并且在任务管理器中也能查看到对应的进程
通过taskkill命令关闭进程
在上一步中,已经可以成功启动进程了,接下来就是如何关闭进程了,在批处理脚本中可以通过 taskkill 命令来杀死进程,我们可以通过这个命令来达到关闭进程的效果
:: 关闭命令显示
@echo off
- :: 需要确认已经将nginx进程加入到系统环境变量中,否则会出现找不到进程的错误,如果不想加入到环境变量,则可以指定完整的程序路径如:start /b nginx.exe
- :: /b 参数指定以后台进程方式来运行程序
- start /b nginx -p D:\Apps\Nginx-1.21.1
:: 杀死进程
:: /f 强制终止指定进程
:: /t 终止指定的进程和由它启动的子进程
:: /im 指定要终止的进程的映像名称。通配符 '*'可用来指定所有任务或映像名称。
taskkill /f /t /im nginx
尝试执行脚本查看结果,得到了如下错误,这是因为在taskkill中必须指定完整的程序名称其中的 .exe 也是不能忽略的
编辑脚本文件,加入完整的进程名称
:: 关闭命令显示
@echo off
...
- taskkill /f /t /im nginx
taskkill /f /t /im nginx.exe
再次执行脚本,可以看到已经显示成功杀死了进程,并且在任务管理器中也已经没有这个进程了
通过进程自身提供的命令来关闭进程
除了可以使用 taskkill 命令来关闭进程外,有些程序自身也有提供了管理进程本身的命令,我们可以通过这些命令来管理进程,比如nginx就有提供了 -s 参数来管理进程的关闭、重启等操作
重启进程对于一些程序本身自带了重启命令的,我们可以直接使用程序本身的命令来对程序进程管理,对于没有的则可以通过杀死进程后在启动进程来达到重启的效果
接收脚本参数通过上面的步骤我们已经了解到了如何通过脚本来控制进程的启动、关闭和重启了,接下来就需要通过参数来控制脚本管理指定的脚本
首先我们需要一个参数来指定要启动的进程,除此之外还需要另一个参数来管理是启动还是关闭进程的指令
编辑脚本文件,加入如下内容
:: 关闭命令显示
@echo off
- :: 杀死进程
- :: /f 强制终止指定进程
- :: /t 终止指定的进程和由它启动的子进程
- :: /im 指定要终止的进程的映像名称。通配符 '*'可用来指定所有任务或映像名称。
- taskkill /f /t /im nginx.exe
:: 通过 %0~%n 可以获取脚本输入的参数,其中 %0 表示脚本的名称
set commandName=%1
set serviceName=%2
echo CommandName: %commandName%
echo ServiceName: %serviceName%
尝试携带参数执行脚本查看结果,可以看到已经能正确获取到了我们输入的参数
接下来就要通过脚本中输入的参数来控制进程的启动和关闭了,编辑脚本,加入如下内容
:: 关闭命令显示
@echo off
:: 开启延迟加载扩展
setlocal EnableDelayedExpansion
...
- echo CommandName: %commandName%
- echo ServiceName: %serviceName%
:: 由于在批处理脚本中没有数组的概念,但我们可以利用变量的延迟加载机制来模拟数组的效果
:: 因为有些程序启动需要指定必要的一些参数,如nginx需要指定运行时目录才能正常启动,所以需要有一个变量来存储默认的启动参数
set args[nginx]=-p D:\Apps\Nginx-1.21.1
:: 利用延迟加载机制达到动态加载变量的目的
set args=!args[%serviceName%]!
:: 设置启动指令数组,使用变量数组来存储指令命令,之后通过动态数组的方式来调用指定的指令
set commands[start]=start /b %serviceName% %args%
set commands[stop]=taskkill /f /t /im %serviceName%.exe
set commands[restart]=%commands[stop]% ^&^& %commands[start]%
:: 执行指令
call !commands[%commandName%]!
尝试执行脚本,可以看到现在已经可以通过脚本来控制nginx的启动和关闭了
为程序配置独立的服务文件
虽然现在已经可以通过该脚本来管理进程的启动和关闭了,但是此脚本还是有着许多的问题,上面我们只是配置了一个进程的启动,可以看到每个进程的启动参数都不一样,如果都放到一个脚本里面,随着进程的增多,脚本也会变得越来越大,所以为了可扩展性我们可以参考linux下的systemctl系统为每个进程编写一个服务脚本
新建脚本文件 Systemctl.bat ,写入如下内容
:: 关闭命令显示
@echo off
:: 开启延迟加载扩展
setlocal EnableDelayedExpansion
:: 接收脚本参数,通过 %0~%n 可以获取脚本输入的参数,其中 %0 表示脚本的名称
set commandName=%1
set serviceName=%2
:: 设置数组,用来限定指令范围
set commands[start]=Start
set commands[stop]=Stop
set commands[restart]=Restart
set commands[status]=Status
:: 设置service文件目录
set servicePath=D:/Bin/services
set serviceFile=%servicePath%/%serviceName%.service
:: 参数验证
if "%commandName%"=="" call :EndBatch "Error: 'command' is not null"
if not defined commands[%commandName%] call :EndBatch "Error: invalid 'command', options command start\stop\restart"
if not exist %serviceFile% call :EndBatch "Error: %serviceName%.service file is not exist"
:: 检查进程是否已运行
if "%commandName%"=="start" tasklist|find /i "%serviceName%.exe" && (
call :EndBatch "%serviceName%.exe in Running"
)
:: 状态查看
if "%commandName%"=="status" (
tasklist /fi "IMAGENAME eq %serviceName%.exe"
call :EndBatch
)
:: 读取文件内容
for /f "delims=," %%i IN (%serviceFile%) do %%i
:: 执行操作
call !service[%commandName%]!
:: 输出执行结果
if %errorlevel%==0 (
call :EndBatch "%serviceName% %commandName% success!"
) else (
call :EndBatch "%serviceName% %commandName% error!"
)
:: 退出脚本
:EndBatch
if not "%~1"=="" echo %~1
call :ExitBatch
goto :eof
:: 强制退出脚本代码块
:ExitBatch - Cleanly exit batch processing, regardless how many CALLs
if not exist "%temp%\ExitBatchYes.txt" call :buildYes
call :CtrlC <"%temp%\ExitBatchYes.txt" 1>nul 2>&1
:CtrlC
cmd /c exit -1073741510
:buildYes - Establish a Yes file for the language used by the OS
pushd "%temp%"
set "yes="
copy nul ExitBatchYes.txt >nul
for /f "delims=(/ tokens=2" %%Y in (
'"copy /-y nul ExitBatchYes.txt <nul"'
) do if not defined yes set "yes=%%Y"
echo %yes%>ExitBatchYes.txt
popd
exit /b
在 Systemctl.bat 文件同级目录下新建 services 目录,并在该目录下新建 nginx.service 文件,写入如下内容
set service[start]=start /b nginx -p D:\Apps\Nginx-1.21.1
set service[stop]=nginx -p D:\Apps\Nginx-1.21.1 -s stop
set service[restart]=nginx -p D:\Apps\Nginx-1.21.1 -s reload
尝试执行脚本,可以看到现在我们已经通过 Systemctl.bat 这个脚本文件来管理进程了,而且我们只需要为需要管理的进程编写service文件,就可以接入管理
在新建一个 php7.3-fpm.service 文件,输入如下内容
set service[start]=start /b php7.3-cgi -b 127.0.0.1:9000
set service[stop]=taskkill /f /t /im php7.3-cgi.exe
set service[restart]=!service[stop]! ^&^& !service[start]!
mysqld.service 文件
set service[start]=net start MySQL8.0
set service[stop]=net stop MySQL8.0
set service[restart]=!service[stop]! ^&^& !service[start]!
免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com