Пакетный файл - поиск слова и извлечение следующего слова в переменной
У меня есть файл журнала, в котором есть много текста в определенном формате. У него есть особая переменная 'SId', которой было присвоено много значений в процессе работы с файлом. Например:
For the first line le=24 we have SId = 23 and then,
on second it's SId = 56, following the be = 45 which......
Я пытаюсь создать пакетный файл, который прочитал бы весь файл и нашел бы последнее назначенное значение переменной 'SId'. Является ли это возможным?
3 ответа
Сначала ответ на вопрос: да, это возможно.
Но думаю, было бы дополнительно интересно всем, кто читает вопрос, как получить последний SId
число. Что ж, действительно трудно использовать ограниченные возможности интерпретатора команд Windows, чтобы получить это число из текстового файла с неизвестным форматом данных. По этой причине это чистое и плохое описание задачи было для меня интересным, и я принял этот вызов кодирования.
Я создал в C:\Temp
файл Test File.log
со следующими тремя строками:
For the first line we have SId = 23 and then,
the second line contains nothing interesting despite SId=x8434
;on third it's "! SId = 56, following SId=8434which ... SId34234 ... !" SId
Последняя строка начинается с точки с запятой, что является проблемой для строк, анализируемых с FOR из-за eol=;
по умолчанию, игнорируя такие строки по умолчанию.
Последняя строка содержит также двойные кавычки, которые требуют отложенного расширения переменной среды при обработке этой строки, и два восклицательных знака, которые могут очень легко привести к замене двух !
и все между ничем при обработке этой строки с включенным отложенным расширением.
Последняя строка содержит также 4 раза SId
, Первые два SId
с разным количеством пробелов вокруг знака равенства, третий SId
без знака равенства и, следовательно, игнорировать, и после последнего SId
есть только один пробел.
Код партии ниже прокомментирован для заинтересованных читателей, за исключением блока кода для определения числа из последних действительных SId
вхождение. Эту часть кода действительно сложно объяснить новичку в пакетном программировании. Определенно легче понять, как работает эта часть кода, удалив @echo off
в верхней части командного файла запустите командный файл из окна командной строки и посмотрите выходные командные строки.
ProcessLine
блок с циклом FOR и подпрограммой GetNumber
выполняется с примером Test File.log
четыре раза со значениями:
= 56, following SId=8434which ... SId34234 ... !" SId
=8434which ... SId34234 ... !" SId
34234 ... !" SId
Примечание: каждый Value
заканчивается завершающим пробелом.
Пакетный код для этой очень общей задачи:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LogFile=C:\Temp\Test File.log"
if not exist "%LogFile%" goto EndBatch
rem Use command FINDSTR to search for all lines containing case-sensitive
rem the string "SId = " without or with spaces around the equal sign and
rem at least one digit. Output by FINDSTR are the lines matching this regular
rem expression with line number and a colon at beginning because of option /N.
rem The option /N is used to make sure that no line with SId starts with a
rem semicolon as those lines would be ignored by default by FOR. The last
rem line with a string matching this simple regular expression is assigned
rem to variable LastLine. Otherwise this environment variable deleted
rem before the loop still does not exist after the loop finished.
set "LastLine="
for /F "delims=" %%I in ('%SystemRoot%\System32\findstr.exe /N /R /C:"SId *= *[0123456789]" "%LogFile%"') do set "LastLine=%%I"
if not defined LastLine goto EndBatch
rem The last line contains perhaps multiple times an equal sign and perhaps
rem even multiple "SId" (secure identifier) strings. So it is necessary to
rem process this last line really the hard way. And it is better to process
rem the line perhaps containing also double quotes or other characters with
rem a special meaning for the Windows command interpreter using delayed
rem environment variable expansion.
setlocal EnableDelayedExpansion
set "Identifier="
:ProcessLine
set "Value=!LastLine:*SID=!"
if not defined Value goto LineProcessed
if "!Value!" == "!LastLine!" goto LineProcessed
for /F "tokens=1,2" %%A in ("!Value!") do (
set "LastID="
if "%%A" == "=" (
set "Number=%%B"
call :GetNumber
) else (
set "Number=%%A"
if "!Number:~0,1!" == "=" (
set "Number=!Number:~1!"
call :GetNumber
)
)
if defined LastID set "Identifier=!LastID!"
set "LastLine=!Value!"
goto ProcessLine
)
set "LastLine=!Value!"
goto ProcessLine
:GetNumber
if not defined Number goto :EOF
set "IsDigit=1"
for /F "delims=0123456789" %%I in ("!Number:~0,1!") do set "IsDigit=0"
if %IsDigit% == 0 goto :EOF
set "LastID=%LastID%%Number:~0,1%"
set "Number=!Number:~1!"
goto GetNumber
rem Pass the last found identifier from current environment with delayed
rem expansion to previous environment on restoring previous environment.
:LineProcessed
endlocal & set "Identifier=%Identifier%"
if not defined Identifier goto EndBatch
echo Last SId found: %Identifier%
rem Other command lines which process the found identifier.
:EndBatch
endlocal
Вывод этого пакетного файла, например Test File.log
является:
Last SId found: 8434
Чтобы понять используемые команды и то, как они работают, откройте окно командной строки, выполните там следующие команды и полностью прочитайте все страницы справки, отображаемые для каждой команды.
call /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
rem /?
set /?
setlocal /?
Одна строка с несколькими командами с использованием командного файла Windows объясняет &
оператор, используемый в одной командной строке.
Партия действительно не сделана для таких вещей. Следующее зависит от некоторых вещей:
- между пробелом SId
а также =
и пробел после =
(можно изменить с помощью find
строка)
- есть допустимый разделитель (пробел, табуляция, запятая, =
) после значения или значения - последняя вещь в строке.
@echo off
SETLOCAL EnableDelayedExpansion
for /f "delims=" %%a in ('type t.txt^|find "SId = "') do (
set "line=%%a"
set "line=!line:*SId =!
set /a "last=!line:~1!" 2>nul
)
echo %last%
Хитрость заключается в том, чтобы удалить что-нибудь из начала (включая) строку поиска (к сожалению, =
не может быть удален с этим), а затем с помощью остальных (минус первый символ, который =
) с set /a
назначить номер переменной.
Существует сообщение об ошибке "отсутствует операнд" в случае строковой части после числа, которое перенаправляется в NUL.
Не видя фактического содержимого файла журнала, было бы трудно представить надежный пример, но, как правило, если SId
первая строка в каждой строке, один из следующих двух FindStr
примеров может быть достаточно:
@For /F "Tokens=1,3" %%A In ('FindStr/BRC:"SId[ ]=[ ][0-9]*" "file.log"') Do @Set "%%A=%%B"
@Echo %SId%
@Pause
@For /F "Tokens=1,3" %%A In ('FindStr/RC:"^SId\ =\ [0-9]*" "file.log"') Do @Set "%%A=%%B"
@Echo %SId%
@Pause
Ваше последнее значение будет присвоено переменной с именем %SId%
, я использовал file.log
как имя вашего файла журнала, отрегулируйте его при необходимости. Чтобы посмотреть опции / переключатели для FindStr
, войти FindStr/?
в командной строке.