Executando o PowerShell analógico de * nix grep de vários arquivos por máscara

3

Existe uma maneira de otimizar o código do PowerShell abaixo (ele agrupa linhas específicas por string contidas em vários arquivos de texto em um único arquivo):

$ErrorActionPreference = "Continue"
Start-Transcript -path D:
grep --no-filename "0xac1cc07a" ./FILES/ubuntlive1mb_?????_201509*.txt >>./0xAC1CC07A.txt
xAC1CC07A.log -append $OutFile = "D:
find ./FILES -name "ubuntlive1mb_?????_201509*.txt" -type f -print0 | xargs -0 grep --no-filename "0xac1cc07a" $1 >>./0xAC1CC07A.txt
xAC1CC07A.txt" echo "filtering 0xAC1CC07A" ForEach ($filenm in ((get-childitem -Path D:\FILES\* -include ubuntlive1mb_?????_201509*.txt -recurse -force))) { $filenm.fullName; (Get-Content $filenm) | select-string "0xAC1CC07A" | Add-Content $OutFile } Stop-Transcript

Funciona bem em pequenas cargas de trabalho, mas em arquivos de texto de 160K (mais de 200GB no total), funciona mais de 4 dias na VM Win2008R2. Surpreendentemente, o Ubuntu 14.04 no hardware virtual similar fez o trabalho em 4 horas:

$ErrorActionPreference = "Continue"
Start-Transcript -path D:
grep --no-filename "0xac1cc07a" ./FILES/ubuntlive1mb_?????_201509*.txt >>./0xAC1CC07A.txt
xAC1CC07A.log -append $OutFile = "D:
find ./FILES -name "ubuntlive1mb_?????_201509*.txt" -type f -print0 | xargs -0 grep --no-filename "0xac1cc07a" $1 >>./0xAC1CC07A.txt
xAC1CC07A.txt" echo "filtering 0xAC1CC07A" ForEach ($filenm in ((get-childitem -Path D:\FILES\* -include ubuntlive1mb_?????_201509*.txt -recurse -force))) { $filenm.fullName; (Get-Content $filenm) | select-string "0xAC1CC07A" | Add-Content $OutFile } Stop-Transcript

Ou mais precisamente:

%pre%

Não sou bom nem no PowerShell nem no * nix, todos os scripts acima foram criados por googling e copy-pasteing.

A caixa do Windows foi otimizada pelo sistema de arquivos, desativando os nomes dos arquivos e a atualização do diretório na lista. O Ubuntu acabou de ser instalado fora da caixa.

    
por Anton Krouglov 12.10.2015 / 11:12

2 respostas

2

Este script muito simples do Powershell deve fazer o que você está procurando:

$OutFile = "D:
Get-ChildItem -Path D:\FILES\ubuntlive1mb_?????_201509*.txt | Select-Object -First 100 | Foreach-Object { Select-String -Path $_ -Pattern "0xAC1CC07A" } | Foreach-Object { Add-Content -Path $OutFile -Value $_.Line }
xAC1CC07A.txt" Get-ChildItem -Path D:\FILES\ubuntlive1mb_?????_201509*.txt -Recurse | Foreach-Object { Select-String -Path $_ -Pattern "0xAC1CC07A" } | Foreach-Object { Add-Content -Path $OutFile -Value $_.Line }

Isso apenas adicionará as linhas correspondentes ao arquivo de texto $ OutFile. Você também pode usar isso para obter os nomes de arquivo ou os números de linha das linhas correspondentes, usando as propriedades Filename, Path e LineNumber, em vez de apenas a propriedade Line.

Se você quiser testar um script que será executado em vários arquivos, mas não quiser esperar que ele termine a verificação de todos eles, use o cmdlet Select-Object para limitar o número de arquivos verifique.

Exemplo:

$OutFile = "D:
Get-ChildItem -Path D:\FILES\ubuntlive1mb_?????_201509*.txt | Select-Object -First 100 | Foreach-Object { Select-String -Path $_ -Pattern "0xAC1CC07A" } | Foreach-Object { Add-Content -Path $OutFile -Value $_.Line }
xAC1CC07A.txt" Get-ChildItem -Path D:\FILES\ubuntlive1mb_?????_201509*.txt -Recurse | Foreach-Object { Select-String -Path $_ -Pattern "0xAC1CC07A" } | Foreach-Object { Add-Content -Path $OutFile -Value $_.Line }

Isso executará o script acima apenas nos primeiros 100 arquivos de texto retornados de Get-ChildItem.

    
por 13.10.2015 / 20:57
2

Você terá uma saída ligeiramente diferente (mas isso pode ser resolvido caso haja uma necessidade), mas pelo que eu vi é um pouco mais rápido, indo apenas para a Select-String diretamente no arquivo, em vez de ficar o conteúdo do arquivo primeiro.

Select-String "0xAC1CC07A" -Path $filenm.FullName | Add-Content $OutFile

Lembre-se de verificar primeiro a saída antes de anexá-la ao arquivo para que você a obtenha da maneira desejada.

Quanto à velocidade; Get-ChildItem é notoriamente lento no PowerShell (como o PowerShell gosta de buscar objetos em vez de apenas representação de texto de objetos) e há várias soluções alternativas para isso.

A linha Get-ChildItem no seu código pode ser otimizada no entanto. Pelo que vi, o uso do Filter é aproximadamente 3,5 vezes mais rápido do que o uso de includes / excludes em um HDD convencional de 7,2k de consumo.

Get-ChildItem -Path "D:\FILES" -Filter "ubuntlive1mb_?????_2015090101*.txt" -Recurse -Force

Se a memória me servir corretamente, versões anteriores do PowerShell tiveram alguns problemas com o filtro, como se você quisesse todos os arquivos com extensão .htm, ele também coletaria os arquivos com a extensão .html (como se você tivesse filtrado *.htm* e não *.htm ), então você pode querer ficar de olho nisso.

    
por 14.10.2015 / 12:02