为何已停止的SQL实例ErrorLevel仍为0?如何跳过实例列表最后一行?
解答:SQL实例检测中的两个常见问题
咱们来逐个解决你遇到的这两个问题:
问题1:测试已停止的实例时,ErrorLevel为何仍为0?
看你批处理里的这段代码:
FINDSTR "!Intance_NAME!" SQL_result.txt IF %ERRORLEVEL% NEQ 0 ( ECHO SQL INSTANCE !Intance_NAME! HAS SOME ISSUE... )
这里的核心问题是延迟变量扩展的使用错误。你已经开启了enabledelayedexpansion,但判断时用的是%ERRORLEVEL%而不是!ERRORLEVEL!。
在for循环里,用%变量%的话,变量值是在循环语句被解析的时候就确定的,而不是每次循环执行时的实时值。也就是说,不管FINDSTR执行结果如何,%ERRORLEVEL%取的都是循环开始前的初始值(通常是0),自然永远不会触发错误判断。
修复方案:把%ERRORLEVEL%改成!ERRORLEVEL!,让它每次循环都读取实时的错误码:
FINDSTR "!Intance_NAME!" SQL_result.txt IF !ERRORLEVEL! NEQ 0 ( ECHO SQL INSTANCE !Intance_NAME! HAS SOME ISSUE... )
另外补充个小优化:其实你可以直接利用sqlcmd本身的返回码,不用依赖FINDSTR。如果sqlcmd连接失败,它会返回非0的ErrorLevel,这样代码可以更简洁:
"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\sqlcmd" -S !Intance_NAME! -e -d master -Q "SELECT @@SERVERNAME" -o SQL_result.txt TIMEOUT /T 2 IF !ERRORLEVEL! NEQ 0 ( ECHO SQL INSTANCE !Intance_NAME! HAS SOME ISSUE... )
问题2:如何跳过Instance_list.txt中的最后一行(循环变量%%a变为'(44')?
这个问题是因为sqlcmd默认会在查询结果末尾输出一行统计信息,比如(44 rows affected),你的for循环读取到这一行时,tokens=1,2会把'(44'作为第一个token。
有两种简单的解决思路:
思路1:让sqlcmd不输出统计信息
修改生成Instance_list.txt的sqlcmd命令,在查询开头加上SET NOCOUNT ON,这样就不会输出最后一行的行数统计:
"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\sqlcmd" -S cms_instance -e -d msdb -Q "SET NOCOUNT ON; SELECT DISTINCT server_name FROM sysmanagement_shared_registered_servers_internal" -o Instance_list.txt
思路2:在循环里过滤掉无效行
如果不想修改查询,可以在for循环里加个判断,跳过包含括号或者"rows affected"的行:
for /f "tokens=1,2 skip=3" %%a in (Instance_list.txt) do ( REM 判断%%a是否包含括号,跳过无效行 echo %%a | findstr /r "[()]" >nul if !ERRORLEVEL! EQU 0 ( goto :NextLoop ) Set Intance_NAME=%%a REM 后面的原有代码... :NextLoop )
或者更简洁的方式,用findstr先过滤掉无效行再读取:
for /f "tokens=1,2 skip=3" %%a in ('type Instance_list.txt ^| findstr /v "rows affected"') do ( Set Intance_NAME=%%a REM 后面的原有代码... )
最终修改后的完整批处理示例
:Start REM get the full list of our instance from CMS to Instance_list.txt "C:\Program Files\Microsoft SQL Server\100\Tools\Binn\sqlcmd" -S cms_instance -e -d msdb -Q "SET NOCOUNT ON; SELECT DISTINCT server_name FROM sysmanagement_shared_registered_servers_internal" -o Instance_list.txt :Run REM Run query against all instances one by one. @echo off setlocal enabledelayedexpansion for /f "tokens=1,2 skip=3" %%a in (Instance_list.txt) do ( Set Intance_NAME=%%a "C:\Program Files\Microsoft SQL Server\100\Tools\Binn\sqlcmd" -S !Intance_NAME! -e -d master -Q "SELECT @@SERVERNAME" -o SQL_result.txt TIMEOUT /T 2 REM 直接用sqlcmd的返回码判断 IF !ERRORLEVEL! NEQ 0 ( ECHO SQL INSTANCE !Intance_NAME! HAS SOME ISSUE... ) )
内容的提问来源于stack exchange,提问作者DBALUKE HUANG
相关产品推荐
相关产品推荐

