PDA

Показать полную графическую версию : Нахождение совпадения в строке и сохранение строк в разные файлы


Страниц : [1] 2

xam2002
10-08-2023, 19:03
Добрый день!

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

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


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

megaloman
11-08-2023, 08:11
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
Большое спасибо!

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

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

Sham
11-08-2023, 19:05
как кодировку по дефолту в PS оставлять? »
сверху добавьте строку $PSDefaultParameterValues['Out-File:Encoding'] = 'default' Кодировка в зависимости от исходной (utf8, oem и т.д. (https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/out-file?view=powershell-5.1#-encoding)). В core версии набор кодировок немного отличается.
ps работает в разы дольше скрипта на cmd »
конечно же FindStr быстрее, но и ps можно оптимизировать под конкретную задачу.

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

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

Uragan66
14-08-2023, 18:00
Можно и мой экзотический вариант попробовать:
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
Гораздо быстрее будет когда 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
Так вроде побыстрее должно быть:

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/55468899/speed-issue-on-match-operation-for-large-text-file

YuS_2
15-08-2023, 18:42
[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
аналог: »

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

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

YuS_2
15-08-2023, 21:19
Не совсем, Get-Content -raw возвращает строку »
это да, но всегда можно отсплитить построчно, это гораздо быстрее чем построчное чтение...

DJ Mogarych
15-08-2023, 21:40
Вот человек целое исследование провёл:


[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 (https://www.serverbrain.org/system-administration/reading-large-text-files-with-powershell.html)

Foreigner
15-08-2023, 23:07
Попробовал с потоком, 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
Foreigner, а если использовать батник megaloman-а?

Foreigner
16-08-2023, 12:24
а если использовать батник megaloman-а? »

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

YuS_2
16-08-2023, 14:51
целое исследование провёл »
Исследование не совсем полноценное... в том смысле, что не указана версия PS. В последних версиях, командлеты оптимизируют, так что цифры могут оказаться другими, при одних и тех же исходных...
а если использовать батник megaloman-а? »
Ночером, если делать будет нечего, попробую потестить на скорострельность разных вариантов...

YuS_2
16-08-2023, 19:23
Итоги тестов, вот такого кода:
$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
Интересное сравнение с 5.1




© OSzone.net 2001-2012