Eu sou novo no ecossistema do Windows. Recebi a tarefa de escrever um programa que pesquisará várias dezenas (talvez até centenas) de milhares de arquivos em busca de uma string específica. A string que deve ser correspondida é um número de série que consiste apenas em números e letras e tem menos de 20 caracteres. Neste momento, meu programa está executando o seguinte comando:
findstr /i /m /s "searchStr" "C:\Directory\To\Search\*.*"
O comando acima funciona, porém é muito lento. Os arquivos que podem conter um número de série específico terão apenas o número de série na primeira linha.
Alguém conhece uma maneira eficiente de pesquisar recursivamente em um diretório todos os arquivos que contêm uma string específica apenas na primeira linha?
Responder1
No PowerShell (v3.0+), talvez...
Get-ChildItem -Path x:\pathto\*.log `
| ForEach-Object {
if (Get-Content -LiteralPath $_ -First 1 `
| Select-String -SimpleMatch -Pattern 'serialnumber')
{
Write-Output $_
}
}
Parâmetros diferentes para Get-ChildItem
subpastas recursivas, etc; para Get-Content
poder obter mais ou menos conteúdo do arquivo; e Select-String
pode realizar correspondências mais complexas (regex, distinção entre maiúsculas e minúsculas, etc.).
Responder2
Posso sugerir algumas opções se você não precisar usar o findstr
, mas antes de tudo você deve verificar se pode restringir a pesquisa a arquivos de um determinado tipo de arquivo, pois isso certamente agilizará as coisas.
Localizador de arquivos LiteNa minha experiência, é mais rápido encontrar arquivos e verificar seu conteúdo. Certifique-se de preencher os campos “nome do arquivo” (se aplicável) e “texto contido”, bem como o diretório inicial.
ag -il "searchStr"
:AGfoi desenvolvido para ser rápido, portanto, deve fornecer resultados rapidamente. Certifique-se de restringir a pesquisa por tipo de arquivo, se puder, embora os arquivos binários já sejam ignorados por padrão. Também disponível emCygwin.find -exec awk 'BEGIN {IGNORECASE=1} NR==1 && /searchStr/ {print FILENAME": "$0}' {} \;
Tente fazer isso se você tiver o Cygwin ou outro ambiente semelhante ao POSIX disponível, para verificar sua ideia de pesquisar apenas a primeira linha. Combinefind
para obter os nomes dos arquivos (e também filtrá-los) eawk
para verificar a primeira linha e imprimi-la junto com o nome do arquivo.find | parallel 'perl -lane '\'' print "$ARGV: $_" if $. == 1 and /searchStr/i '\'' {}'
Outra ideia para tentar agilizar as coisas é colocar núcleos e threads disponíveis para funcionar: é isso queParalelo GNUé para. Este exemplo é esportivoperl
, mas faz o mesmo queawk
acima3.
. Aqui está um detalhamento do comando:find
procure arquivos no diretório atual e seus subdiretórios. Você pode especificar um diretório diferente para procurar e um padrão ou extensão de arquivo para filtrar:find /cygdrive/c/Directory/To/Search -iname "*.txt"
.|
"pipe", ou seja, alimentar a lista de resultados para o próximo comando.parallel
execute o próximo comando em paralelo.perl
linguagem de script que se destaca na manipulação de arquivos de texto, pode substituirsed
ouawk
.-lane
conjunto útil de opções para perl one-liners.'\''
apóstrofo escapado, necessário porque já abrimos um apóstrofo definido depois deparallel
.print "$ARGV: $_"
imprima o nome do arquivo ($ARGV
), dois pontos, um espaço e a linha completa ($_
).if
execute a instrução anterior apenas se as seguintes condições forem atendidas.$. == 1
o número da linha ($.
) é igual a um (1
), ou seja, estamos olhando para a primeira linha do arquivo.and
a seguinte condição também deve ser atendida./searchStr/i
a linha que está sendo examinada contém o textosearchStr
, sem distinção entre maiúsculas e minúsculas.'\''
outro apóstrofo escapado marca o fim daperl
instrução.{}
this será substituído porparallel
cada um dos nomes de arquivos transmitidos porfind
.'
final daparallel
instrução.
Atualizar:Ambos awk
e perl
leem o arquivo inteiro, mesmo que as ações estejam vinculadas apenas à primeira linha. A solução é parar explicitamente a elaboração na linha 2:
find -exec awk 'BEGIN {IGNORECASE=1} NR > 1 {exit} /searchStr/ {print FILENAME": "$0}' {} \;
find | parallel 'perl -lape '\'' exit if $. == 2; print "$ARGV: $_" if /searchStr/i '\'' {}'