В вашем скрипте неверная логика; for /F
читает одну строку за другой, поэтому перед записью одной выходной строки необходимо собрать данные трех строк.
Вот пример того, как выполнить вашу задачу, не используя for /F
, а перенаправление ввода (<
) и set /P
для чтения файла журнала:
@echo off
setlocal EnableDelayedExpansion
for /F %%C in ('^< "abc.log" find /C /V ""') do set /A "COUNT=(%%C+1)/2"
set "FIRST=#"
< "abc.log" > "abc.csv" (
for /L %%I in (1,1,%COUNT%) do (
set "LINE1=" & set /P LINE1=""
if defined LINE1 (
set "LINE2=" & set /P LINE2=""
set "LINE3=" & set /P LINE3=""
if defined FIRST (
echo Name,City,Country
set "FIRST="
)
echo(!LINE1:*:=!,!LINE2:*:=!,!LINE3:*:=!
)
)
)
endlocal
Это зависит от указанного формата вашего файла журнала, поэтому он не проверяет строки, оставленные двоеточиям.
Вот более гибкий подход, основанный на вышеупомянутом, но он собирает значения полей по их именам, которые содержатся в предварительно заданном настраиваемом списке (константа _LIST
). Одна или несколько пустых строк завершают возвращенную строку. Если определенное имя поля не может быть найдено в текущем обработанном блоке файла журнала, его возвращенное поле CSV будет пустым. Это код:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem // Define constants here:
set "_INPUT=abc.log" & rem // (log file to process)
set "_OUTPUT=abc.csv" & rem // (CSV file to return)
set "_LIST=Name,City,Country" & rem /* (comma-separated list of field names, which must
rem not contain any of the following characters:
rem `:`, `,`, `*`, `?`, `<`, `>`, `!`, `"`, `=`) */
set "_SEPARATOR=," & rem /* (separator character to be used; the default is `,`;
rem the following separator characters are forbidden:
rem `!`, `^`, `&`, `(`, `)`, `<`, `>`, `|`) */
set "_QUOTED=#" & rem // (if not empty, defines to quote the returned items)
set "_HEADER=#" & rem // (if not empty, defines to write a header row)
set "_SEPARATOR=!_SEPARATOR!," & set "_SEPARATOR=!_SEPARATOR:~,1!"
if not defined _QUOTED (set "QUOTE=") else set "QUOTE="^" & rem/^"
for /F "delims==" %%D in ('2^> nul set $ARRAY[') do set "%%D="
for /F %%C in ('^< "abc.log" find /C /V ""') do set /A "COUNT=%%C+1"
< "abc.log" > "abc.csv" (
set "FLAG=" & if defined _HEADER if defined _LIST (
echo(%QUOTE%!_LIST:,=%QUOTE%%_SEPARATOR%%QUOTE%!%QUOTE%
) else echo(%QUOTE%%QUOTE%
for /L %%I in (1,1,%COUNT%) do (
set "LINE=" & set /P LINE=""
if defined LINE (
for /F "delims=: eol=:" %%J in ("!LINE!") do set "$ARRAY[%%J]=!LINE:*:=!"
set "FLAG=#"
) else (
if defined FLAG if defined _LIST (
set "COLL=" & for %%J in ("!_LIST:,=","!") do (
set "COLL=!COLL!%_SEPARATOR%%QUOTE%!$ARRAY[%%~J]!%QUOTE%"
set "$ARRAY[%%~J]="
)
echo(!COLL:~1!
) else echo(%QUOTE%%QUOTE%
set "FLAG="
)
)
)
endlocal
exit /B
Этот сценарий собирает элементы списка в некотором массиве $ARRAY[]
, индексами которого являются имена полей, поэтому строки, оставленные до (первого) двоеточия каждой строки в блоке файла журнала, и значения элементов которых равны строки справа от (первого) двоеточия и могут выглядеть следующим образом (относительно первого блока данных вашего примера журнала):
$ARRAY[Name]=Mark
$ARRAY[City]=London
$ARRAY[Country]=UK