Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   Нахождение совпадения в строке и сохранение строк в разные файлы (http://forum.oszone.net/showthread.php?t=353994)

xam2002 10-08-2023 19:03 3013746

Нахождение совпадения в строке и сохранение строк в разные файлы
 
Добрый день!

Помогите хотя бы с направлением, куда копать.

Есть огромный (несколько млн строк) текстовый файл с логами. Нужно прочитать строку, найти в ней совпадение имени сервиса и в зависимости от этого сохранить строку в другой файл.

Код:

20230810 16:44 service1 online
20230810 16:45 service2 online
20230810 17:48 service1 offline
20230810 17:49 service2 offline

В итоге получить файлы service1.log и service2.log

Заранее спасибо!

DJ Mogarych 10-08-2023 22:05 3013772

Powershell
Код:

gc 'C:\temp\big.log' |% {
    if ($_ -match 'service1') {$_ >> 'C:\temp\service1.log'}
    if ($_ -match 'service2') {$_ >> 'C:\temp\service2.log'}
}


Sham 10-08-2023 23:49 3013779

Код:

gc 'file.log' | ? { $_ -match '\d{8} \d{2}:\d{2} (service1|service2)' } | % { $_ >> "c:\logs\$($Matches[1]).log" }

megaloman 11-08-2023 08:11 3013787

cmd
Код:

        @Set "FileIn=Z:\Box_In\Есть текстовый файл.txt"

        >"Z:\Box_In\service1.txt" FindStr /I " service1 " "%FileIn%"
        >"Z:\Box_In\service2.txt" FindStr /I " service2 " "%FileIn%"


xam2002 11-08-2023 18:08 3013807

Большое спасибо!

Все варианты рабочие, но при тестовом прогоне (1,9млн строк, 300mb) выяснилось, что ps работает в разы дольше скрипта на cmd (ps - 690 секунд, cmd - 2) и сохраняет файл по умолчанию в UTF-16.

ЗЫ Если не сложно, подскажите как кодировку по дефолту в PS оставлять?

Sham 11-08-2023 19:05 3013811

Цитата:

Цитата xam2002
как кодировку по дефолту в PS оставлять? »

сверху добавьте строку
Код:

$PSDefaultParameterValues['Out-File:Encoding'] = 'default'
Кодировка в зависимости от исходной (utf8, oem и т.д.). В core версии набор кодировок немного отличается.
Цитата:

Цитата xam2002
ps работает в разы дольше скрипта на cmd »

конечно же FindStr быстрее, но и ps можно оптимизировать под конкретную задачу.

xam2002 14-08-2023 14:23 3013888

Sham,
Большое спасибо, забыл, что можно использовать глобальные переменные, пытался с параметром в самом out-file играть.

Цитата:

Цитата Sham
конечно же FindStr быстрее, но и ps можно оптимизировать под конкретную задачу. »

А можно поподробнее, где почитать? Все-таки ps намного гибче, и возможно в будущем пригодится.

Uragan66 14-08-2023 18:00 3013908

Можно и мой экзотический вариант попробовать:
Код:

ForEach ($str in (Get-Content .\service.txt  -Encoding utf8)) {
($str | Select-String -Pattern '[\S\s]*service1[\S\s]*').Matches | ForEach {$_.Value | Out-File -Append .\service1.log -Encoding utf8}
($str | Select-String -Pattern '[\S\s]*service2[\S\s]*').Matches | ForEach {$_.Value | Out-File -Append .\service2.log -Encoding utf8}
}

Насколько будет быстро работать, не знаю, нет такого большого файла на проверить...

Foreigner 14-08-2023 23:13 3013930

Гораздо быстрее будет когда Select-String читает файл, а не получает его содержимое через пайп.

Код:

Select-String 'service1' file.log -raw | Out-File service1.log
Select-String 'service2' file.log -raw | Out-File service2.log


DJ Mogarych 15-08-2023 13:17 3013953

Так вроде побыстрее должно быть:
Код:

function ExtractTo-Chunk ($in,$out,$regex) {
    [regex]$regex = $regex
    [System.IO.File]::AppendAllText("$out", ([System.IO.File]::ReadAllLines("$in") -match $regex -join [Environment]::NewLine))
}

ExtractTo-Chunk -in "C:\temp\big.log" -out "C:\temp\service1.log" -regex "service1"
ExtractTo-Chunk -in "C:\temp\big.log" -out "C:\temp\service2.log" -regex "service2"

Ref: https://stackoverflow.com/questions/...arge-text-file

YuS_2 15-08-2023 18:42 3013984

Цитата:

Цитата DJ Mogarych
[System.IO.File]::ReadAllLines("$in") »

аналог:
Код:

gc $in -raw
а вообще, для ускорения, можно и потоковое чтение/запись задействовать, что-то типа%
Код:

$reader = [io.streamreader]::new('1.txt')
$writer = [io.streamwriter]::new('2.txt')
 
while ($reader.peek() -ne -1){
    $writer.write($reader.readline()) # тут можно различные проверки замутить
}
 
$reader.close()
$writer.close()


Foreigner 15-08-2023 18:58 3013985

Цитата:

Цитата YuS_2
аналог: »

Не совсем, Get-Content -raw возвращает строку, a [System.IO.File]::ReadAllLines() массив строк.

A streamreader, это действительно хорошая идея.

YuS_2 15-08-2023 21:19 3013986

Цитата:

Цитата Foreigner
Не совсем, Get-Content -raw возвращает строку »

это да, но всегда можно отсплитить построчно, это гораздо быстрее чем построчное чтение...

DJ Mogarych 15-08-2023 21:40 3013987

Вот человек целое исследование провёл:
Цитата:


[System.IO.File]::ReadLines(): 6 seconds
Get-Content -ReadCount 1000: 7 seconds
Switch -File: 10 seconds
[System.IO.File]::OpenText().readtoend(): 10 seconds
[System.IO.File]::ReadAllText(): 13 seconds
[System.IO.File]::ReadAllLines(): 16 seconds
Get-Content -Raw: 46 seconds
Get-Content: 229 seconds

Reading large text files with Powershell

Foreigner 15-08-2023 23:07 3013993

Попробовал с потоком, 1млн строк разбился на два файла за 6 сек:

Код:

$reader  = [io.streamreader]::new("$pwd/file.log")
$writer1 = [io.streamwriter]::new("$pwd/service1.log")
$writer2 = [io.streamwriter]::new("$pwd/service2.log")

while ($reader.peek() -ne -1)
{
    switch -regex ($out = $reader.readline())
    {
        'service1' { $writer1.write($out + "`n") }
        'service2' { $writer2.write($out + "`n") }
    }
}

$reader.close()
$writer1.close()
$writer2.close()


DJ Mogarych 16-08-2023 10:54 3014008

Foreigner, а если использовать батник megaloman-а?

Foreigner 16-08-2023 12:24 3014014

Цитата:

Цитата DJ Mogarych
а если использовать батник megaloman-а? »

Я не могу, линукс

YuS_2 16-08-2023 14:51 3014023

Цитата:

Цитата DJ Mogarych
целое исследование провёл »

Исследование не совсем полноценное... в том смысле, что не указана версия PS. В последних версиях, командлеты оптимизируют, так что цифры могут оказаться другими, при одних и тех же исходных...
Цитата:

Цитата DJ Mogarych
а если использовать батник megaloman-а? »

Ночером, если делать будет нечего, попробую потестить на скорострельность разных вариантов...

YuS_2 16-08-2023 19:23 3014029

Итоги тестов, вот такого кода:
тестовый код
Код:

$file = 'out1500000.txt'

'------'
'1 - gc $file'
(measure-command{
1..3|%{$arr = $null}{$arr = gc $file}
write-host $($arr.count) -for red
}).totalseconds
'------'
'2 - gc $file -ReadCount 10000'
(measure-command{
1..3|%{$arr = $null}{$arr = gc $file -ReadCount 10000}
write-host $($arr.count) -for red
}).totalseconds
'------'
'3 - (gc $file -raw) -split "`n"'
(measure-command{
1..3|%{$arr = $null}{$arr = (gc $file -raw) -split "`n"}
write-host $($arr.count) -for red
}).totalseconds
'------'
'4 - switch -file $file {default {$psitem}}'
(measure-command{
1..3|%{$arr = $null}{$arr = switch -file $file {default {$psitem}}}
write-host $($arr.count) -for red
}).totalseconds
'------'
'5 - [io.file]::readalltext($file) -split "`n"'
(measure-command{
1..3|%{$arr = $null}{$arr = [io.file]::readalltext($file) -split "`n"}
write-host $($arr.count) -for red
}).totalseconds
'------'
'6 - [io.file]::readalllines($file)'
(measure-command{
1..3|%{$arr = $null}{$arr = [io.file]::readalllines($file)}
write-host $($arr.count) -for red
}).totalseconds
'------'
'7 - [io.file]::readlines($file) -split "`n"'
(measure-command{
1..3|%{$arr = $null}{$arr = [io.file]::readlines($file) -split "`n"}
write-host $($arr.count) -for red
}).totalseconds
'------'
'8 - [io.file]::opentext($file).readtoend() -split "`n"'
(measure-command{
1..3|%{$arr = $null}{$arr = [io.file]::opentext($file).readtoend() -split "`n"}
write-host $($arr.count) -for red
}).totalseconds
'------'
'9 - $reader.readtoend() -split "`n"'
(measure-command{
1..3|%{$arr = $null}{
    $reader = [io.streamreader]::new($file)
    $arr = $reader.readtoend() -split "`n"
    $reader.close()
}
write-host $($arr.count) -for red
}).totalseconds


- чтобы получить более-менее корректные сравнения, цель работы каждого блока была такой:
Считать из файла 1500000 строк и получить массив такого же количества строк.
PS 7.3.6
Цитата:

------
1 - gc $file
1500000
135,3993815
------
2 - gc $file -ReadCount 10000
150
4,5613858
------
3 - (gc $file -raw) -split "`n"
1500001
3,8927897
------
4 - switch -file $file {default {$psitem}}
1500000
1,8711774
------
5 - [io.file]::readalltext($file) -split "`n"
1500001
1,4145144
------
6 - [io.file]::readalllines($file)
1500000
0,8467002
------
7 - [io.file]::readlines($file) -split "`n"
1500000
2,5423216
------
8 - [io.file]::opentext($file).readtoend() -split "`n"
1500001
1,4478526
------
9 - $reader.readtoend() -split "`n"
1500001
1,7025707
PS 5.1
Цитата:

------
1 - gc $file
1500000
71,0913368
------
2 - gc $file -ReadCount 10000
150
2,0562238
------
3 - (gc $file -raw) -split "`n"
1500001
5,4825919
------
4 - switch -file $file {default {$psitem}}
1500000
1,6654813
------
5 - [io.file]::readalltext($file) -split "`n"
1500001
3,9344098
------
6 - [io.file]::readalllines($file)
1500000
0,5840069
------
7 - [io.file]::readlines($file) -split "`n"
1500000
2,4861966
------
8 - [io.file]::opentext($file).readtoend() -split "`n"
1500001
3,6093053
------
9 - $reader.readtoend() -split "`n"
1500001
3,2849391
- понятно, что безоговорочным победителем скорочтения массива строк, становится [io.file]::readalllines($file), ибо никаких дополнительных разбивок не требует...

Foreigner 16-08-2023 19:40 3014030

Интересное сравнение с 5.1

YuS_2 17-08-2023 07:30 3014046

Цитата:

Цитата Foreigner
Интересное сравнение с 5.1 »

Да, видимо, "дооптимизировались" разрабы, что семерка, со встроенными командлетами, оказалась медленнее, чем 5.1... возможно, что какое-то влияние оказало то, что Windows Terminal является консолью по умолчанию, надо будет попробовать отключить его и запустить тесты в стандартной консоли... но не думаю, что результат будет сильно отличаться...

DJ Mogarych 17-08-2023 09:01 3014052

А откуда кто берёт файлы конских размеров для тестов?

Foreigner 17-08-2023 10:21 3014057

Цитата:

Цитата DJ Mogarych
А откуда кто берёт файлы конских размеров для тестов? »


Я просто скопировал пример файла в стартовом топике и:

Код:

(gcb) * 250000 | Out-file file.log

YuS_2 17-08-2023 17:40 3014085

Цитата:

Цитата DJ Mogarych
А откуда кто берёт файлы конских размеров для тестов? »

или так:
Код:

$cnt = 1500000
$str = new-object text.stringbuilder
for ($i = 0; $i -le $cnt; $i++){
        $null = $str.append("012345678`r`n")
}
$str.tostring()|add-content out.txt -enc utf8

Цитата:

Цитата YuS_2
надо будет попробовать отключить его и запустить тесты в стандартной консоли »

в общем, значительных отличий нет... 0.5 - 1 сек. туда-сюда, как в плюс так и минус, от теста к тесту гуляют циферки...


Время: 23:57.

Время: 23:57.
© OSzone.net 2001-