批量FOR循环管道命令

时间:2015-03-19 15:21:22

标签: batch-file for-loop

基本上我试图从服务器的文本文件中读取,连续ping它们,并在每个服务器重新启动时输出时间戳(查找“请求超时”。

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

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

有没有人知道如何同时运行每个CMD窗口而无需关闭每个先前的窗口?

谢谢!

1 个答案:

答案 0 :(得分:1)

您的设计不起作用: - (

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

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

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

您最好的选择是编写VBScript,JScript或PowerShell脚本以持续ping服务器,并在检测到超时时写出带有时间戳的消息。

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

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

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选项在同一控制台窗口中运行多个进程,但如果两个进程同时尝试写入控制台,则可能会出现乱码输出的风险。这可以通过进程打开文件进行写入时获得的独占锁来解决。有关如何提供帮助的一些指示,请参阅How do you have shared log files under Windows?。该链接用于共享日志文件,但很容易适用于共享控制台访问。

我已经使用我的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!
  )
)