Я написал пакетный скрипт для захвата определенной строки местоположения из текстового файла, например:
Текстовый файл содержит:
Copyright Version 5.39
Network activity progressing...
Thread Time(s) Throughput(KB/s) Avg B / Compl
====== ======= ================ =============
0 600.088 73245.829 45502.632
1 594.574 84312.667 44974.835
2 594.569 62862.184 44547.486
3 599.665 66407.148 45056.270
4 600.633 61846.742 44741.495
5 594.569 45967.918 46745.891
6 594.937 72678.901 45115.861
7 593.981 86081.374 45148.288
8 593.975 35448.661 44118.093
9 602.451 64144.439 44708.118
10 599.760 26404.342 53411.916
11 594.569 64959.044 44525.327
12 594.564 63125.969 44512.966
13 602.999 71045.335 45266.114
14 599.719 19782.849 54192.569
15 594.574 61670.399 44341.198
16 599.681 71804.247 44954.492
17 593.980 21731.533 43903.776
18 593.979 22436.796 43919.327
19 599.748 21296.983 53880.446
##### Totals: #####
Bytes(MEG) realtime(s) Avg Frame Size Throughput(MB/s)
================ =========== ============== ================
639903.106318 600.002 4289.297 1066.502
Throughput(Buffers/s) Cycles/Byte Buffers
===================== =========== =============
17064.032 41.043 10238449.701
DPCs(count/s) Pkts(num/DPC) Intr(count/s) Pkts(num/intr)
============= ============= =============== ==============
3081479.450 0.085 2302796.649 0.113
Packets Sent Packets Received Retransmits Errors Avg. CPU %
============ ================ =========== ====== ==========
66199455 156432871 4 0 99.998
Всего в текстовом файле 58 строк, и мне нужно будет получить значение Throughput(MB/s), которое выделено в строке 43, и 4-ю строку, из приведенного выше примера, это 1066.502.
Итак, я создал пакетный скрипт для фильтрации числа:
set "lom1 = "
for /f "skip=48 delims = " %%i in LOM_1.log) do if not defined lom1 set "lom1=%%i"
echo !lom1! >> temp1.txt
for /f "tokens=4" %%j in temp1.txt do echo %%j >> result.log
Но теперь исходный текст содержит ошибки и увеличивает случайные строки, например:
Copyright Version 5.39
Network activity progressing...
ERROR: WaitForWorkerThreads failed: WaitForMultipleObjects returned an unexpected value
ERROR: DoWork failed: WaitForWorkerThreads(threads_finished) timed out
ERROR: StartSenderReceiver in thread: 9 failed: closesocket, GetLastError: 10093 - Either the application has not called WSAStartup, or WSAStartup failed.
ERROR: StartSenderReceiver in thread: 13 failed: closesocket, GetLastError: 10093 - Either the application has not called WSAStartup, or WSAStartup failed.
ERROR: StartSenderReceiver in thread: 16 failed: closesocket, GetLastError: 10093 - Either the application has not called WSAStartup, or WSAStartup failed.
Thread Time(s) Throughput(KB/s) Avg B / Compl
====== ======= ================ =============
0 600.088 73245.829 45502.632
1 594.574 84312.667 44974.835
2 594.569 62862.184 44547.486
3 599.665 66407.148 45056.270
4 600.633 61846.742 44741.495
5 594.569 45967.918 46745.891
6 594.937 72678.901 45115.861
7 593.981 86081.374 45148.288
8 593.975 35448.661 44118.093
9 602.451 64144.439 44708.118
10 599.760 26404.342 53411.916
11 594.569 64959.044 44525.327
12 594.564 63125.969 44512.966
13 602.999 71045.335 45266.114
14 599.719 19782.849 54192.569
15 594.574 61670.399 44341.198
16 599.681 71804.247 44954.492
17 593.980 21731.533 43903.776
18 593.979 22436.796 43919.327
19 599.748 21296.983 53880.446
##### Totals: #####
Bytes(MEG) realtime(s) Avg Frame Size Throughput(MB/s)
================ =========== ============== ================
639903.106318 600.002 4289.297 1066.502
Throughput(Buffers/s) Cycles/Byte Buffers
===================== =========== =============
17064.032 41.043 10238449.701
DPCs(count/s) Pkts(num/DPC) Intr(count/s) Pkts(num/intr)
============= ============= =============== ==============
3081479.450 0.085 2302796.649 0.113
Packets Sent Packets Received Retransmits Errors Avg. CPU %
============ ================ =========== ====== ==========
66199455 156432871 4 0 99.998
Вы можете видеть, что в текстовом файле есть дополнительные строки ERROR, это означает, что я все еще не могу использовать команду for /f "skip=48" для фильтрации правильной строки, поэтому я хотел бы знать, можно ли использовать какую-либо пакетную команду или параметры for /f для считать от последней строки, чтобы всегда был фиксированный номер строки, например, в текстовом содержимом выше. Если я считаю от последней строки и мне нужна строка 16th, то я могу продолжить экспорт строки 16th ( считать с последней строки), а затем захватить строку 4th для числа.
Я пытался гуглить, но не нашел полезной информации.
@Magoo звучит хорошо, но извините, не могли бы вы дать мне пример кода, чтобы я мог изменить его в соответствии с тем, что мне нужно, извините, я здесь новичок...
Если вам нужна только цифра Throughput(MB/s) из утилиты командной строки ntttcp.exe, нужен ли вам вообще текстовый файл?
@Compo Да, мне все еще нужен текстовый файл в качестве журнала тестирования, скажем, он будет сгенерирован сценарием стресс-теста, будет выполняться не только один раз, но и в течение ночи, по 5 минут каждый цикл, поэтому будет много файлов журналов и их необходимо сохранить, для тестового сценария мне нужно собрать все показатели производительности в один файл для быстрого просмотра (поэтому мне не нужно открывать каждый файл журнала, чтобы проверить номер), но исходный журнал все равно необходимо сохранить для дальнейшей отладки.
Итак, вы хотите сделать это для нескольких файлов, как они называются? должен быть шаблон именования файлов, если это делается в запланированном цикле. Гораздо больше смысла в решении, которое читает их все, а не только одно.
На DosTips.com есть замечательная функция, которую можно использовать для извлечения разделов файла. dostips.com/DtCodeCmdLib.php#Function.extractFileSection
В приведенном выше файле примера всего 49 строк, а не 58, и Throughput(MB/s) находится в строке 32 вместо 43. Итак, то, что вы сказали (всего 58 строк...) неверно.
@Compo Предположим, что тестовый сценарий будет выполнять тест в течение 5 минут, а затем перезагрузит систему, после загрузки ОС снова запустит 5-минутный стресс-тест и зациклится на ночь. Мой тестовый сценарий может переименовывать журнал испытаний и сохранять его для каждого цикла тестирования, так что это не является проблемой для нескольких файлов журнала испытаний, и мой тестовый сценарий будет делать то же самое в журнале испытаний, когда проводится 5-минутный стресс-тест. завершено, и создается журнал испытаний.
@Compo И это то, что я сказал выше: записать показатель производительности в другой текстовый файл для сбора всех показателей производительности с помощью циклических тестов, что позволяет мне легко быстро просмотреть все показатели производительности после завершения ночного стресс-теста.
@phuclv не совсем, пустую строку также необходимо учитывать, поскольку для командного файла она даже пуста, но все равно остается строкой. Содержимое примера, которое я публикую, представляет собой всего лишь 100% копирование и вставку сюда, включая пустые строки.
@JackyLee, конечно, пустые строки учитываются. Я скопировал то, что вы написали выше, вставил в файл и пользуюсь wc -l





Вот один из примеров того, как я могу попытаться выполнить задачу получения значений пропускной способности из каждого файла журнала:
@Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
PushD "P:\ath To\Log Directory" 2>NUL || Exit /B
( For /F "Tokens=1-2 Delims=:" %%G In ('%SystemRoot%\System32\findstr.exe
/INR "Throughput(MB/s)" "lom_*.log" 2^>NUL') Do Call :Sub "%%G" "%%H"
) 1>"%~dp0result.log"
Pause
PopD
EndLocal
GoTo :EOF
:Sub
Set /A "_l=%~2 + 1"
For /F "Tokens=4" %%I In ('%SystemRoot%\System32\more.com +%_l% "%~1"'
) Do Echo %%I& GoTo :EOF
Очевидно, вам следует изменить путь к файлу журнала в четвертой строке, и обратите внимание, что я предположил, что имена файлов журнала имеют шаблон lom_*.log. Полученный файл будет находиться в том же каталоге, что и ваш командный файл.
Обратите внимание: если вы обрабатываете только один файл за один запуск пакетного файла, а не целый каталог, полный их, вам нужно будет изменить только 1> на 1>> в восьмой строке.
Я несколько неправильно прочитал ваши данные, отметив, что теперь требуется Throughput(MB/s) токен 6, а необходимые данные находятся в токене 4.
Не уверен, хотите ли вы обрабатывать несколько файлов — если нет, внешний цикл %%y не нужен и замените имя файла на %%y в оставшемся цикле.
%%b получит токен 4 и %%c токен 6 в обработанных строках
@ECHO OFF
SETLOCAL
rem The following setting for the directory and filenames are names
rem that I use for testing and deliberately includes spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
SET "outfile=%destdir%\outfile.txt"
(
FOR %%y IN ("%sourcedir%\q78165354*.txt") DO (
SET "required = "
SET "grabnext = "
FOR /f "tokens=4,6delims= " %%b IN ('findstr /v /L /c:" = " "%%y"') DO IF /i "%%c"= = "Throughput(MB/s)" (SET "grabnext=y") ELSE (
IF NOT DEFINED required IF DEFINED grabnext SET required=%%b&ECHO %%b %%y
)
)
)>"%outfile%"
GOTO :EOF
rem Всегда проверяйте тестовый каталог перед применением к реальным данным.
Для тестирования я использовал файлы с именем q78165354*.txt, содержащие ваши данные.
Здесь другой и более простой подход. Вместо того, чтобы получить строку на две строки ниже Throughput(MB/s), мы можем получить строку на три строки выше Throughput(Buffers/s), которую можно получить с помощью одной команды findstr.
@echo off
setlocal EnableDelayedExpansion
rem Get a CR+LF (NewLine) variable
for /F %%a in ('copy /Z "%~F0" NUL') do set ^"NL=%%a^
%Don't remove this line%
^"
rem Get the appropriate line and get its 4th token
findstr "!NL!!NL!!NL!Throughput(Buffers/s)" LOM_1.log | for /F "tokens=4" %%a in ('more') do echo %%a
Если вы хотите обработать несколько файлов *.log, просто вставьте команды findstr ... | for ... в цикл обработки файлов.
РЕДАКТИРОВАТЬ 21.03.2024: Получить номер ошибки.
Я читал ваш запрос в комментариях ниже ответ phuclv о получении номера «Ошибки». Получить такое число очень просто в батнике:
Если Packets Sent Packets Received Retransmits Errors Avg. CPU % — последний раздел в файле, просто сделайте следующее:
for /F "tokens=4" %%a in (LOM_1.log) do set "Errors=%%a"
и это все! ;)
@Compo: Боюсь, ты прочитал не мой ответ...
Заметил это, Аацини, извини.
В PowerShell это намного проще: если содержимое не исправлено, вы можете использовать это, чтобы сопоставить строку 2nd после Throughput(MB/s) и получить последнее слово:
(sls -Co 0,2 'Throughput(MB/s)' -S file.txt).Context.PostContext.Split(' ')[-1]
Если вы хотите получить именно последний токен в строке 43, используйте это:
(gc file.txt | select -Skip 42 -F 1).Split(' ')[-1]
(some command).Split(' ') разделит результат some command по пробелу ' ' на массив, а затем [-1] получит последний элемент массива
Полное объяснение и версии без псевдонимов ниже.
В любом случае ваш вопрос не соответствует названию. Если вы хотите, чтобы строка Nth считалась снизу, что похоже на tail -<N> file.txt | head -1 в *nix, то это совершенно другое. Чтобы получить 17-ю строку из последней строки, просто используйте это
gc file.txt -Ta 17 | select -F 1
Вы можете вызвать его из cmd, если вы действительно не можете избежать cmd следующим образом:
powershell -C "Get-Content file.txt -Tail 17 | Select-Object -First 1"
powershell -Command "(gc file.txt | select -Skip 42 -F 1).Split(' ')[-1]"
Но просто избегайте cmd в новом коде, в PowerShell все проще.
Вот полная версия приведенных выше команд без псевдонимов.
# Get the 43th line by skipping the first 42, then
# split the string by space ' ' and get the last word
(Get-Content file.txt | Select-Object -Skip 42 -First 1).Split(' ')[-1]
# Same as above but counting up skipping the last 16 lines instead
(Get-Content file.txt -Tail 17 | Select-Object -First 1).Split(' ')[-1]
# Find the line containing 'Throughput(MB/s)' and 2 lines of context after that,
# matching the string literally instead of regex, then extract the last word
# on the 2nd context line
(Select-String -Context 0,2 'Throughput(MB/s)' `
-SimpleMatch file.txt).Context.PostContext.Split(' ')[-1]
дополнительный вопрос: если я хочу получить номер «Ошибки», каким должно быть последнее значение в следующей команде: powershell (Select-String -Context 0,2 'Errors' ` -SimpleMatch LOM_1.log).Context.PostContext.Split (' ')[ценить]
@JackyLee это просто обычная индексация массива, как в Python или некоторых других языках сценариев. Для массива a тогда a[i] — это i-й элемент с начала, если i >= 0, и с конца, если i < =, поэтому i = -1 берет последний элемент.
phuclv Да, но попробовал -2, чтобы захватить два последних элемента, но не удалось. Если я использую -1, то я получу число «Средний процент ЦП» (последний элемент, как вы сказали), но не «Ошибки» из моего примера журнала в первом сообщении, поэтому я просто попробовал -2, чтобы получить количество «Ошибок», но безуспешно.
@JackyLee, это потому, что обычная функция String.Split(), используемая в этом случае, просто допускает использование одного символа-разделителя в наборе. Вам понадобится оператор -split, если вы хотите разделить, используя несколько последовательных символов-разделителей: PS /Users/phluu> ((Select-String -Context 0,2 "Avg. CPU %" -SimpleMatch file.txt).Context.PostContext -split '\s+')[-4..-1]. Это напечатает последние 4 элемента
@JackyLee В качестве альтернативы вы можете использовать перегрузку, позволяющую обрезать: ((Select-String -Context 0,2 "Avg. CPU %" -S file.txt).Context.PostContext.Split(' ', [StringSplitOptions]::TrimEntries + [StringSplitOptions]::RemoveEmptyEntries))[-5..-2]: будут напечатаны последние элементы со 2 по 5. Более короткий метод: (-split (sls -Co 0,2 "Avg. CPU %" -S file.txt).Context.PostContext)[-4..-1]
Вы можете прочитать файл, использовать find, чтобы определить номер строки Througput(MB/s), затем добавить к нему единицу, чтобы получить номер строки, результатом которой является ваш 4-й токен:
@echo off & set "tput = "
for /F "delims=[]" %%i in ('find /N "Throughput(MB/s)" "LOM_1.log"') do set /a ln=1+%%i
for /f "usebackq skip=%ln%tokens=4delims= " %%i in ("LOM_1.log") do if not defined tput set "tput=%%i"
echo %tput%
Добавьте >> result.log в последнюю строку, если вам нужно сохранить его в файле.
Я бы подошел к этому, просто используя
for /f`` loop on the output of afindstr`, который игнорирует строки, содержащие=, Используя логическое значение, чтобы определить, является ли четвертый токен строкиThroughput(MB/s), и когда это логическое значениеset, grab the fourth token of the next line, exit thefor` и отобразить.