如何从 cmd 输出读取字符串并在批处理脚本中返回该值?

如何从 cmd 输出读取字符串并在批处理脚本中返回该值?

我的 Windows 服务器通过两个默认网关连接到远程办公网络。

默认网关

172.20.0.1    Primary
172.20.0.254  Secondary

// Secondary connected with
// 4G SIM card VPN 

服务器的初始配置

172.20.0.10   IP Address
255.255.255.0 Subnet Mask
172.20.0.1    Default Gateway

我想在服务器上运行一个批处理脚本,检测主网关何时172.20.0.1出现故障并自动将服务器切换到辅助网关172.20.0.254,反之亦然。

我想通过定期 ping 当前网关来检测故障。

Pinging 172.20.105.1 with 32 bytes of data:

Reply from 172.20.0.1: bytes=32 time<1ms TTL=255

Reply from 172.20.0.1: bytes=32 time=1ms TTL=255

Reply from 172.20.0.1: bytes=32 time=1ms TTL=255

当 ping 失败时,它不会返回“TTL=”并且脚本会假定网关已关闭并切换到另一个网关。

@echo off
setlocal enableextensions enabledelayedexpansion

:loop
ping 172.20.0.1 -n 2
timeout /t 10
set "str1=%~1"

if not "%str1:"TTL="=%" == "%str1%" (
     echo "Primary Gateway NOT reachable"
     netsh interface ipv4 set address name="Ethernet" static 172.20.0.10 255.255.255.0 172.20.0.254   
    )

echo "Primary Data UP"
goto loop

有没有更好的方法在服务器端完成这个任务?

答案1

@echo off && setlocal enabledelayedexpansion

set "_gtw#254=netsh interface ipv4 set address name="Ethernet" static 172.20.0.10 255.255.255.0 172.20.0.254"
set "_gtw#001=!_gtw#254:172.20.0.254=172.20.0.1!"
set "_msg#001=Primary Gateway NOT reachable"
set "_msg#002=Primary Data UP"

mode.com con: cols=60 lines=5
for /f tokens^=1*delims^=#skip^=4 %%i in ('echo;prompt $E#$H^|cmd.exe
    ')do set "_$E=%%~i" & set "_bs=%%~j"

%:^)
title <nul
set "_dns=" <nul
echo/!_$E![1F!_$E![0J

for /f tokens^=2*delims^=: %%i in ('netsh interface ipv4 show config ^| findstr "DNS.*DHCP.*[0-9]"
   ')do for /f %%n in ('%ComSpec% /u /c echo="%%~i"^<nul ^| find /v " "')do set "_dns=!_dns!%%~n"

title Gateway: !_dns!
echo/!_bs!!_$E![1;33m Please^^! Wait for few seconds...!_$E![0m

ping !_dns! -n 6 -w 500 | find /c "TTL" | find "6" >nul && goto %:^) || =;(
     if "!_dns!" == "172.20.0.1" 2>nul =;(
           echo; !_msg#001!
           !_gtw#254!
           echo; !_msg#002:Primary=Secondary!
        ); else 2>nul =;( 
           echo; !_msg#001:Primary=Secondary!
           !_gtw#001!
           echo; !_msg#002!
        );=
    );= 

timeout /t 00010 /nobreak >nul 
echo/!_$E![1F!_$E![0J!_$E![1F!_$E![0J!_$E!
goto %:^)

或者...

@echo off && setlocal enabledelayedexpansion

set "_gtw#254=static 172.20.0.10 255.255.255.0 172.20.0.254"
set "_msg#001=Primary Gateway NOT reachable" 
set "_msg#002=Primary Data UP"

set "_gtw#254=netsh interface ipv4 set address name="Ethernet" !_gtw#254!"
set "_gtw#001=!_gtw#254:172.20.0.254=172.20.0.1!"

for /f tokens^=1*delims^=#skip^=4 %%i in ('echo;prompt $E#$H^|cmd.exe
    ')do set "_$E=%%~i" & set "_bs=%%~j" & mode.com con: cols=60 lines=5

%:^)
title <nul & set "_dns=" <nul & echo/!_$E![1F!_$E![0J

for /f tokens^=2*delims^=: %%i in ('netsh interface ipv4 show config ^| findstr "DNS.*DHCP.*[0-9]"
   ')do for /f %%n in ('%ComSpec% /u /c echo="%%~i"^<nul ^| find /v " "')do set "_dns=!_dns!%%~n"

title Gateway: !_dns! & echo/!_$E![1;33m Please^^! Wait for few seconds...!_$E![0m

ping !_dns! -n 6 -w 500 | find /c "TTL" | find "6" >nul && goto %:^) || =;(
     if "!_dns!" == "172.20.0.1" 2>nul =;(echo; !_msg#001! & !_gtw#254! & echo; !_msg#002:Primary=Secondary!
        ); else 2>nul =;( echo; !_msg#001:Primary=Secondary! & !_gtw#001! & echo; !_msg#002! );=
    );= & timeout /t 00010 /nobreak >nul & echo/!_$E![1F!_$E![0J!_$E![1F!_$E![0J!_$E! & goto %:^)

有没有更好的方法在服务器端完成这个任务?

  • 是的,如果我考虑以下几点:

1.问题中的代码并未识别当前网关是否为主网关,也未识别是否已对辅助网关进行更改。


2.如果辅助网关发生故障,则永远不会将网关从辅助网关更改为主网关。


3.如果您的主要网关正在使用并且相应失败,则您的echonetsh命令将被执行,但仅限于第一个网关正在使用并且第一次进入循环的情况,之后,第二个网关将始终被重复配置以供使用,即使在离线时也是如此。


4.%~1set "str1=%~1"由于缺乏关于所使用的参数的引用和/或比较的目的,您的问题毫无意义,其中参数%~1定义一个变量str1并且比较它的子字符串("%str1:"TTL="=%"):

set "str1=%~1"

if not "%str1:"TTL="=%" == "%str1%"

附言从现在开始,参考你的answer...


5.上述项目中观察到/指出的项目1.2.3.在你的行动/效果中重复出现,也出现在你当前回答


6.使用重定向重定向 ping 命令时无需创建文件,使用省略输出的替换>nul并将重定向到运算符&&(return 0), ||(return non 0) 可以带来相同的结果,而无需额外的ìfs,请记住,在关闭 ,创建的文件将保留在那里而不会被使用。

ping 172.20.0.1 -n 2 > pingtest.txt
 if %errorlevel%==0 goto waiting

ping 172.20.0.1 -n 2 >nul && goto waiting

附言从现在起,请参考此答案的第 1 版

将来会进行编辑并添加动作/命令描述,但这会在我的空闲/空闲时间尽快完成。


A)定义变量,并允许在此定义或命令中使用子字符串,从而允许相关更改网关 .1网关.254和:

set "_gtw#254=netsh interface ipv4 set address name="Ethernet" static 172.20.0.10 255.255.255.0 172.20.0.254"
set "_gtw#001=!_gtw#254:172.20.0.254=172.20.0.1!"
set "_msg#001=Primary Gateway NOT reachable"
set "_msg#002=Primary Data UP"
...
if "!_dns!" == "172.20.0.1" 2>nul =;(
           echo; !_msg#001!
           !_gtw#254!
           echo; !_msg#002:Primary=Secondary!
           );= else =;( 
           echo; !_msg#001:Primary=Secondary!
           !_gtw#001!
           echo; !_msg#002!
           );=

b)首先在循环中获取命令的输出,并使用适当的令牌/分隔符获取当前正在使用的 DNS/网关的 IP,然后在第二个循环中,使用以下命令过滤/删除任何空格:netsh interface ipv4 show configfor /ffor /ffind /aVoid " " ...

for /f tokens^=2*delims^=: %%i in ('netsh interface ipv4 show config ^| findstr "DNS.*DHCP.*[0-9]"
   ')do for /f %%n in ('%ComSpec% /u /c echo="%%~i"^>nul ^| find /v " "')do set "_dns=!_dns!%%~n"

C)使用的命令ping将花费大约 10 秒,因此显示已获得的 DNS / 网关的标题以及在此期间显示的一些消息可用于向用户发出正在运行活动的信号:

在此处输入图片描述

title Gateway: !_dns!
echo/!_bs!!_$E![1;33m Please^^! Wait for few seconds...!_$E![0m

d)对于在:loop,据我推测它的使用不是偶尔的,而且它的执行将持续一段时间,没有理由不进行一些额外的阐述,比如使用文本颜色美国国家标准而不是用cls,只在相关的行上执行此操作,此外还要保持屏幕尺寸“已调整” mode要显示的文本:


for /f tokens^=1*delims^=#skip^=4 %%i in ('echo;prompt $E#$H^|cmd.exe
    ')do set "_$E=%%~i" & set "_bs=%%~j" & mode.com con: cols=60 lines=5

:: $E set _$E [%%~i] to ESC Character 
:: $H set _bs [%%~j] to BackSpace Character

:: Display size/buffer - number of columns wide and number of lines deep:
:: MODE    CON[:] [COLS=c] [LINES=n]
:: mode.com con:   cols=60  lines=5
title >nul & ... echo/!_$E![1F!_$E![0J 
...
title Gateway: ... echo/!_$E![1;33m Please^^! Wait for few seconds...!_$E![0m

e)建立一个ping数字-n 6)并计算()出现的次数find /CountTTL使用重定向器进行输出|并省略屏幕上的输出(>nul),在此命令处理中,也可以充分利用运算符&&||return 0根据和定义相关行动retunr non 0

ping !_dns! -n 6 | find /c "TTL" | find "6" <nul && .. || ...

your ping cmd && (
     echo/ Retuned 0  
    )  ||  (
     echo/ Retuned non 0
    )  

ping !_dns! -n 6 -w 500 | find /c "TTL" | find "6" >nul && goto %:^)
ping !_dns! -n 6 -w 500 | find /c "TTL" | find "6" >nul || if condition() else()

F)使用条件中的运算符return 0,返回以重新DNS/Gateway开始获取操作,并pingtimeout适当的间隔再次执行,如果“TTL”计数不匹配,则if假设条件为return non 0,并DNS/Gateway使用varible:substrings=?与条件相关的文本和命令编写当前假设:

if "!_dns!" == "172.20.0.1" 2>nul =;(
           echo; !_msg#001!
           !_gtw#254!
           echo; !_msg#002:Primary=Secondary!
           );= else =;( 
           echo; !_msg#001:Primary=Secondary!
           !_gtw#001!
           echo; !_msg#002!
           );=


G)在上述项目中处理完操作之后,timeout还需要执行命令循环以进行新的诊断,并根据命令返回执行相关操作,然后等待,然后清理(echo/ ESC[ANSI codes)使用的行并重定向到启动新循环的goto标签%:^),完美满足这些操作:

timeout /t 00010 /nobreak >nul 
echo/!_$E![1F!_$E![0J!_$E![1F!_$E![0J!_$E!
goto %:^)


阅读更多:

答案2

谢谢大家。我找到了一个更简单的方法。方法如下。

@echo off

cls
:starting
ping 172.20.0.1 -n 2 > pingtest.txt

c:\windows\system32\findstr.exe "TTL=" pingtest.txt

if %errorlevel%==0 goto waiting

echo "DATA is DOWN switching to BACKUP Network"

netsh interface ipv4 set address name="Ethernet" static 172.20.0.2 255.255.255.0 172.20.0.254   

timeout /t  60

:waiting

echo "DATA is working witing for delay"
timeout /t  60

goto starting

相关内容