批处理 FOR 循环管道命令

batch FOR loop piped command

基本上我试图从服务器的文本文件中读取,连续 ping 它们,并在每个服务器重新启动时输出时间戳 (find "Request timed out.")

for /f "delims=" %%a in (Servers_List.txt) do (
     start cmd /k ping -t %%a | find "Request timed out."
) && (Echo %%a rebooted at %time%.)

它在单独的 window 中启动每个服务器 ping -t,直到我添加 | find 件,然后在随后的每个 window 关闭后,它一次只启动一个。

有谁知道同时 运行 每个 CMD window 而无需关闭每个之前 window 的方法?

谢谢!

你的设计不行:-(

您的第一个问题是您正在通过管道传输 START 命令的输出,但您想通过管道传输 PING 的输出。这可以通过将管道转义为 ^|.

来解决

您的条件命令连接也有类似的问题 - 您需要 ^&^& 而不是 &&1

但最大的问题是您的 ECHO 在管道关闭之前不会执行,这是永远不会的! FIND 将在检测到第一个超时线后继续寻找其他超时线。直到管道关闭后它才会结束,直到 FIND 终止后您的 ECHO 才会 运行。

最好的办法是编写 VBScript、JScript 或 PowerShell 脚本来连续 ping 服务器,并在检测到超时时写出带有时间戳的消息。

您可以编写一个批处理脚本来遍历您的服务器列表并为每个服务器启动一个新的自定义 ping 进程。或者您可以将所有内容放入单个 VBScript(或 JScript 或 Powershell)脚本中。

也许以下 link 之一可以帮助您入门:

http://windowsitpro.com/scripting/how-can-i-use-vbscript-script-ping-machine

http://www.sems.org/2013/07/little-vbscript-to-continously-ping-a-host-with-timestamplog/

https://thwack.solarwinds.com/docs/DOC-135033

我假设您理想情况下希望将所有输​​出显示在一个屏幕上。您可以使用 START /B 选项 运行 同一控制台 window 中的多个进程,但是如果两个进程试图在同一控制台写入控制台,那么您 运行 有乱码输出的风险同时。这可以通过进程打开文件进行写入时获得的独占锁来解决。请参阅 How do you have shared log files under Windows? 以获取有关此功能如何提供帮助的一些指示。 link 用于共享日志文件,但很容易适应共享控制台访问。

我已经用我的 JREPL.BAT utility 破解了一个解决方案。在架构上这是一个令人费解的可憎行为,但它确实有效!它 运行 对每台服务器都是一个无休止的 PING 过程,所有这些过程都在同一个控制台中并行进行。每个进程将其输出通过管道传输到 JREPL,JREPL 检测服务器是否响应并将带有时间戳的消息写入控制台和日志文件。日志文件还用作锁定文件,以协调进程之间的共享访问。每个进程都会跟踪最后一次服务器状态,并且只有在状态发生变化时才会写入消息。

@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment

::***** Batch code *******
@echo off
setlocal enableDelayedExpansion
set "first="
copy nul serverStatus.log >nul
for /f "delims=" %%A in (Servers_List.txt) do if not defined first (
  set "first=%%A"
) else (
  start /b cmd /c ping -t %%A ^| jrepl "^Request timed out|^Reply from " "log('%%A','DOWN')|log('%%A','UP')" /t "|" /jmatch /jlib "%~f0"
)
if defined first ping -t %first% | jrepl "^Request timed out|^Reply from " "log('%first%','DOWN')|log('%first%','UP')" /t "|" /jmatch /a /jlib "%~f0"
exit /b

****** JScript code ******/
var status = 'initial';
var fso = new ActiveXObject("Scripting.FileSystemObject");
var file;

function log( server, newStatus ) {
  if (status!=newStatus) {
    status=newStatus;
    var msg=new Date().toString()+'  '+server+' is '+newStatus;
    while (!openFile());
    file.WriteLine(msg);
    output.WriteLine(msg);
    file.Close();
  }
  return false;
}

function openFile() {
  try {
    file = fso.OpenTextFile('serverStatus.log',8);
    return true;
  } catch(e) {
    return false;
  }
}

但是,我不明白为什么有必要 运行 并行处理。在我看来,你可以简单地进入一个循环遍历服务器的无限循环,并分别 PING 每个服务器,写出状态。这是一个简单的批处理脚本,它就是这样做的。同样,它仅在检测到状态变化时才打印出一条消息。

@echo off
setlocal enableDelayedExpansion
for /l %%N in () do for /f "delims=" %%S in (Servers_List.txt) do (
  ping /n 1 %%S | findstr /bc:"Request timed out" >nul && set "status='DOWN'" || SET "status=UP"
  if "!status!" neq "!%%S!" (
    set "%%S=!status!"
    echo !date! !time!  %%S is !status!
  )
)