Обработка вывода программ

Обсуждение вопросов программирования (WSH/JScript/VBScript, CMD), проблемы и решения
Ответить
nhutils
Сообщения: 582
Зарегистрирован: 09 дек 2009, 18:08
Контактная информация:

Обработка вывода программ

Сообщение nhutils »

WSH предоставляет полезную возможность обработки вывода консольных программ "на лету". Для чего это может быть полезно? Рассмотрим вывод программы ping:

Код: Выделить всё

Pinging www.yandex.ru [93.158.134.203] with 32 bytes of data:

Reply from 93.158.134.203: bytes=32 time=83ms TTL=54
Reply from 93.158.134.203: bytes=32 time=76ms TTL=54
…
Reply from 93.158.134.203: bytes=32 time=175ms TTL=54
Destination host unreachable.
Destination host unreachable.
Reply from 93.158.134.203: bytes=32 time=75ms TTL=54
…
Reply from 93.158.134.203: bytes=32 time=77ms TTL=54
Ping statistics for 93.158.134.203:
    Packets: Sent = 1000, Received = 970, Lost = 30 (3% loss),
Approximate round trip times in milli-seconds:
    Minimum = 74ms, Maximum = 183ms, Average = 76ms
Выводимая информация полезна, но зачастую хотелось бы:
  • Знать не только число потерянных пакетов, но и в какое именно время происходили потери, чтобы можно было точно знать, сколько было периодов отсутствия связи, когда и какой продолжительности.
  • Анализировать содержание строки, численные показатели и выполнять какие-нибудь действия, если, например, ответ пришёл, но time > 200ms.
  • Выполнять действия (например, уведомление по смс) по потере пакетов, причём не по окончании сеанса работы программы, а в момент, когда произошла потеря.
  • Фильтровать вывод программы, например, показывать только проблемные строки (потери и time > 200ms), но не показывать строки, где ответ получен, и параметры в норме (time < 200 ms).
  • Корректировать вывод программы, например, переводить текст на другой язык или добавлять уточняющую информацию.
  • Показывать вывод программы в окне и одновременно с этим дублировать его в файл.
Все эти, а также многие другие пожелания можно реализовать с помощью скриптов за сравнительно короткое время. Примеры написаны на JScript, но всё то же самое можно написать и на VBScript.

Все примеры основаны на использовании метода Exec и построчной обработке потока вывода StdOut. Как только в поток поступает строка, мы её получаем в переменную line и обрабатываем.

Код: Выделить всё

var shell = WScript.CreateObject("WScript.Shell");
var ping = shell.Exec("ping http://www.yandex.ru -n 100");
while (!ping.StdOut.AtEndOfStream) {
  var line = ping.StdOut.ReadLine(); // считываем строку
  // обрабатываем строку…
}
Первый пример – простановка отметки времени для каждой строки. В цикле обработки выводим сначала строку времени, затем строку вывода программы ping:

Код: Выделить всё

WScript.Echo(date_to_string(new Date()) + " " + line);
Функция date_to_string преобразует дату в строку и может быть реализована, например, так:

Код: Выделить всё

function numtofixed(number,length){
  var s = number.toString();
  while (s.length < length)
    s="0"+s;
  return s;
}

function date_to_string(date) {
  return numtofixed(date.getDate(),2) + "." + 
    numtofixed(date.getMonth() + 1,2) + "." +
    numtofixed(date.getYear(),4) + " " +
    numtofixed(date.getHours(),2) + "." +
    numtofixed(date.getMinutes(),2) + "." +
    numtofixed(date.getSeconds(),2);
}
В этом простом примере каждая строка, даже пустая, будет начинаться с даты и времени:

Код: Выделить всё

21.03.2012 23.02.13 Pinging www.yandex.ru [93.158.134.203] with 32 bytes of data:
21.03.2012 23.02.13 
21.03.2012 23.02.13 Reply from 93.158.134.203: bytes=32 time=83ms TTL=54
21.03.2012 23.02.14 Reply from 93.158.134.203: bytes=32 time=76ms TTL=54
…
21.03.2012 23.02.44 Reply from 93.158.134.203: bytes=32 time=77ms TTL=54
Ping statistics for 93.158.134.203:
    Packets: Sent = 30, Received = 30, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 74ms, Maximum = 83ms, Average = 76ms

nhutils
Сообщения: 582
Зарегистрирован: 09 дек 2009, 18:08
Контактная информация:

Re: Обработка вывода программ

Сообщение nhutils »

Следующий пример – как ограничить вывод программы и не отображать строки, где получен ответный пакет, и время triptime находится в допустимых пределах.
Для этого проверяем каждую строку на соответствие образцу «Reply from 93.158.134.203: bytes=32 time=83ms TTL=54» с помощью регулярного выражения, выделяем значение time и, если оно не превышает 200 мс, не обрабатываем эту строку:

Код: Выделить всё

  var reply_re = 
    new RegExp("[1-9][0-9]*\.[1-9][0-9]*\.[1-9][0-9]*\.[1-9][0-9]*:" +
      ".*=[1-9][0-9]*.*=[1-9][0-9]*.*TTL=[1-9][0-9]*");
  while (!ping.StdOut.AtEndOfStream) {
    var line = ping.StdOut.ReadLine();
    if (line.match(reply_re)) {
      var re = new RegExp("[0-9]+","g");
      var numbers = line.match(re);
      var triptime = numbers[5];
      if (triptime < 200) // если меньше 200 мс…
        continue;         // …то переходим к следующей строке
    }
    // дальнейшая обработка строки …
  }

Ответить