Преобразование данных журнала в CSV-файл с желаемым форматом - PullRequest
0 голосов
/ 04 июля 2018

У меня есть данные журнала как:

Name:Mark
City:London
Country:UK

Name:Ben
City:Paris
Country:France

Name:Tom
City:Athens
Country:Greece

И мне нужно сделать вывод в формате CSV в формате:

Name   City      Country
Mark   London    UK
Ben    Paris     France
Tom    Athens    Greece

Пакет, который я создал для этого, является простым для преобразования в CSV. Что выглядит следующим образом:

@echo off

cd /d %~dp0
set infilenm=abc.log
set outfilenm=abc.csv
set beforestr=
set afterstr=, 

type nul >%outfilenm%

setlocal enabledelayedexpansion

for /f "tokens=1,2,3 delims=" %%A in (%infilenm%) do (   
    set line=%%A      
    echo !line:%beforestr%=%afterstr%!>>%outfilenm%
)
endlocal

exit /b

Поскольку я новичок в пакетном скрипте, может ли кто-нибудь помочь мне в этом!

Ответы [ 4 ]

0 голосов
/ 05 июля 2018

Решение PowerShell, которое не заботится о количестве свойств адреса.
Единственная необходимая константа - это пустая строка, разделяющая адреса и
двоеточие между property:value

При необходимости он может быть вызван из пакета (более подробно по теме)

  • Используется регулярное выражение для разбиения на разделы. (адрес),
    разбить каждый раздел на строки и разбить каждый строка в свойство и значение.
  • вставляет свойства со значением в каждый новый адрес,
  • настройка отсутствующих свойств в результирующей таблице automagically выполнена PowerShell
  • отображение в виде таблицы с шириной столбца, автоматически определяемой Format-Table

## Q:\Test\2018\07\04\SO_51166380.ps1
$InputFile = '.\abc.log'
$OutputFile= '.\abc.csv'

$Sections = ((Get-Content $InputFile -Raw) -split "`r?`n *`r?`n" -ne '')

$Csv = ForEach($Section in $Sections){
    $Address = New-Object PSCustomObject
    ForEach($PropVal in ($Section -Split "`r?`n" -ne '')){
        $Prop,$Val = $PropVal.Split(':',2)
        Add-Member -InputObject $Address `
                   -NotePropertyName $Prop `
                   -NotePropertyValue $Val
    }
    $Address
}
$Csv | Format-Table -Auto
$Csv | Export-Csv $OutputFile -NoTypeInformation

Пример вывода с измененным abc.log

> type abc.log
Name:Mark
City:London
Country:UK
LastName:Anonymus

Name:Ben
Country:France

Name:Tom
City:Athens

Name:Antonio
City:Mexico
Country:Mexico

> .\SO_51166380.ps1

Name    City   Country LastName
----    ----   ------- --------
Mark    London UK      Anonymus
Ben            France
Tom     Athens
Antonio Mexico Mexico

> type .\abc.csv
"Name","City","Country","LastName"
"Mark","London","UK","Anonymus"
"Ben",,"France",
"Tom","Athens",,
"Antonio","Mexico","Mexico",
0 голосов
/ 04 июля 2018
@echo off
setlocal

set "output=abc.csv"
2> "%output%" echo.

set "line=Name,City,Country"
call :write

for /f "tokens=1,* delims=:" %%A in (abc.log) do call :append %%A %%B
exit /b

:append
setlocal
set  "key=%~1"
set  "value=%~2"
endlocal & (
    if /i "%key%" == "Name" set "line=%value%"
    if /i "%key%" == "City" set "line=%line%,%value%"
    if /i "%key%" == "Country" set "line=%line%,%value%"& call :write
)
exit /b

:write
setlocal
for /f "tokens=1-3 delims=," %%A in ("%line%") do (
    set "a=%%~A          "
    set "b=%%~B          "
    set "c=%%~C          "
)
>> "%output%" echo %a:~,10% %b:~,10% %c:~,10%
set "line="
exit /b

Заголовок сначала записывается в файл, устанавливая его в переменная с именем line и вызывает метку :write для форматирования и запишите в выходной файл csv.

Цикл for разбивает каждую строку на : с помощью токенов 1,* получить 1-й токен до : и 2-й токен как остаток после :. Называется метка :append объединить строку на основе 1-го токена. Если токен равен Country, затем вызов на метку :write форматирует строку и записывает ее в выходной файл csv.

0 голосов
/ 04 июля 2018

Ваш вопрос неясен в нескольких моментах, поэтому мы можем только догадываться ...

@echo off
setlocal EnableDelayedExpansion

rem Put here the width of the output columns
set "width=10"

set "spaces="
for /L %%i in (1,1,%width%) do set "spaces= !spaces!"
set "head=" & "out=" & set "output="
for /F "tokens=1-3 delims=:" %%a in ('findstr /N "^" logData.txt') do (
   if "%%b" neq "" (
      if not defined output (
         set "col=%%b%spaces%"
         set "head=!head!!col:~0,%width%!"
         set "out=!out!^!%%b:~0,%width%^!"
      )
      set "%%b=%%c%spaces%"
   ) else (
      if not defined output (
         echo !head!
         set "output=!out!"
      )
      for /F %%o in ("!output!") do echo %%o
      for %%a in (!head!) do set "%%a=%spaces%"
   )
)

С этим logData.txt :

Name:Mark
City:London
Country:UK

Name:Ben
Country:France

Name:Tom
City:Athens

Name:Antonio
City:Mexico
Country:Mexico

Это вывод:

Name      City      Country
Mark      London    UK
Ben                 France
Tom       Athens
Antonio   Mexico    Mexico

Эта программа требует, чтобы первая группа данных включала все столбцы, а за последней группой данных следовала пустая строка ...

0 голосов
/ 04 июля 2018

В вашем скрипте неверная логика; 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...