Извлечь найденную строку + последующую строку из текстового файла - PullRequest
2 голосов
/ 20 января 2012

Я пытаюсь написать командный файл, который сканирует несколько файлов и ищет строку "WARNING". Пока у меня есть:

FORFILES -m*.f08 -C"CMD /C FINDSTR /N "WARNING"  ECHO @FILE >> ListOfWARNINGS

Проблема первая: он не печатает каждую найденную строку в новой строке.

Проблема вторая: как я могу изменить код и добавить оператор IF, чтобы он также печатал строку, следующую за строкой, где был найден WARNING.

Ответы [ 3 ]

2 голосов
/ 20 января 2012

Я думаю, что для получения следующей строки вам действительно придется зацикливать файлы и контент, поскольку ни forfiles, ни найти поддержку, насколько я знаю,

@echo off
setlocal enabledelayedexpansion
for %%f in (*.txt) do (
    echo Search %%f
    for /f "usebackq eol= delims=] tokens=1*" %%l in (`find /n /v "" "%%f"`) do (
        set line=%%m
        if !printnext!==1 (
            echo.%%m >> ListOfWARNINGS
            set printnext=0
        ) else (
            if not [!line!]==[] if not !line!==!line:WARNING=X! (
                echo %%m >> ListOfWARNINGS
                set printnext=1
            ) else (
                set printnext=0
            )
        )
    )
)

Здесь if not !line!==!line:WARNING=X! обнаруживаетсопоставьте, спросив, равна ли строка себе после того, как ПРЕДУПРЕЖДЕНИЕ заменено на X.

C:\null>type a.txt

line 1
M O D E L S U M M A R Y
WARNING XXXXXXX
Line after warning
NUMBER OF CBAR ELEMENTS = 18655
lorem ipsum lorem ipsum lorem ipsum
WARNING ZZZZZZZ


C:\null>x.bat
Search a.txt

C:\null>type ListOfWARNINGS
WARNING XXXXXXX
Line after warning
WARNING ZZZZZZZ

C:\null>
1 голос
/ 21 января 2012

Решение Alex K прекрасно работает и работает хорошо, если файлы относительно небольшие.Но если файлы становятся большими, производительность может стать серьезной проблемой.

Я настроил тест с 4 файлами - 3 маленьких файла размером менее 1 КБ, плюс 1 большой файл ~ 1 МБ.В файлах разбросаны ПРЕДУПРЕЖДЕНИЯ, в том числе около начала и конца большого файла.

Решение Alex K заняло 4,75 минут для завершения!Проблема в том, что весь набор результатов FINDSTR в FOR IN () должен быть кэширован, и Windows делает это очень неэффективно с большими наборами данных.

Также у решения есть потенциальная проблема в том, что оно повредит любые имена файлов и / или строки данных, которые содержат ! из-за задержки расширения.Это можно исправить, включив и отключив отложенное расширение, также по мере необходимости сохраняя значения переменных через границу ENDLOCAL.


Гораздо быстрее записать результаты во временный файл и затем использоватьFOR / F для чтения временного файла.Я изменил код, чтобы использовать временный файл (не показан), и время было сокращено до 43 секунд.


Но есть еще более быстрое решение.Цикл FOR чрезвычайно медленный при чтении файла по сравнению со скоростью FINDSTR.Ниже приведено решение, которое использует FINDSTR для поиска каждого файла один раз для каждого предупреждения, плюс еще 2 раза.Это выглядит как дополнительная работа, но время для завершения моего теста сокращено до 1 секунда !

Это решение также устраняет любые проблемы, связанные с ! в именах файлов.или содержимое файла.

Решение оптимизировано для случаев, когда количество ПРЕДУПРЕЖДЕНИЙ относительно мало по сравнению с количеством строк в файле.Если число ПРЕДУПРЕЖДЕНИЙ начинает приближаться к количеству строк в файле, то оно фактически станет медленнее, чем среднее решение, описанное выше.

Это решение также добавляет к каждому предупреждению префикс с именем файла и строкой.number.

@echo off
setlocal disableDelayedExpansion
set searchFiles="*.f08"
set outFile="ListOfWARNINGS"
set tempFile="%temp%\warnings%random%.txt"
set tempFile2="%temp%\warnings2_%random%.txt"
(
  for /f "tokens=1,2 delims=:" %%A in ('findstr /m WARNING %searchFiles% nul') do (
    findstr /n "^" "%%A" nul >%tempFile%
    echo(>>%tempFile%
    set "file=%%A"
    set "next=0"
    setlocal enableDelayedExpansion
    findstr /n WARNING "!file!" >%tempFile2%
    for /f "usebackq delims=:" %%N in (%tempFile2%) do (
      if %%N==!next! (set "current=") else set current=/c:"!file!:%%N:"
      set /a "next=%%N+1"
      findstr /bi !current! /c:"!file!:!next!:" %tempFile%
    )
    endlocal
  )
)>%outFile%
del %tempFile% 2>nul
del %tempFile2% 2>nul

Опция /I в последнем FINDSTR логически не обязательна.Он предназначен для защиты от ошибки, когда у FINDSTR иногда возникают проблемы с несколькими строками поиска букв различной длины.

1 голос
/ 20 января 2012

Попробуй вот так,

@ECHO OFF
:TOP
  IF (%1)==() GOTO END
  ECHO Value is "%1" and still running...
 SHIFT
 GOTO TOP
:END

И посмотрите эту ссылку также

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...