Como pesquisar uma string em vários arquivos e retornar os nomes dos arquivos no Powershell?

303

Comecei a aprender PowerShell há alguns dias e não consegui encontrar nada no Google que fizesse o que eu precisava. Por isso, aceite minha pergunta.

Me pediram para substituir algumas seqüências de texto em vários arquivos. Não sei necessariamente a extensão dos possíveis arquivos de destino e também não sei a localização deles. Até agora, consegui navegar recursivamente no diretório ( get-ChildItem -recurse) e encontrar a string que estava procurando com get-content e select-string:

Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy"

O problema é que posso ver as ocorrências do texto que estou procurando, mas não sei como dizer ao PS para retornar o caminho e o nome de todos os arquivos correspondentes.

Como posso obter o nome e o local dos arquivos que contêm a expressão que estou procurando?

Bluz
fonte
2
Talvez edite a pergunta para ser mais genérica. A resposta a esta questão não tem nada a ver com JBoss ou seu aplicativo que você está trabalhando no que parece ...
Kolob Canyon
5
Acabei de ver seu comentário e editei minha pergunta ... 2 anos depois! mais vale tarde do que nunca .. :) #
1155

Respostas:

469

Isso deve fornecer a localização dos arquivos que contêm seu padrão:

Get-ChildItem -Recurse | Select-String "dummy" -List | Select Path
Jon Z
fonte
3
E se você também quiser mover esses arquivos? ... Estou recebendo um erro com esse erro, onde não consigo ingressar em um | Mover item para o final disso.
Rud3y
6
Move-Item não tem nameparâmetro. Tente adicionar| %{Move-Item $_.name <destination>}
jon Z
49
Get-ChildItem -Recurse | Select-String "dummy" -List | Select Pathretorna apenas a primeira correspondência para cada arquivo, portanto, pode ser um pouco mais eficiente e evita a necessidade de agrupá-los
ben
5
vale a pena notar que você pode filtrar para apenas um determinado tipo de arquivo, dizem txtos arquivos, se você usar Get-ChildItem -Recurse -Filter *.txtem vez
Girardi
@ rud3y Eu sugiro que você escreva em um script usando um foreachloop, se estiver fazendo grandes operações como essa. Torna-se muito complicado quando você tenta fazer tudo isso em uma linha e é muito fácil cometer um grande erro. Falo por experiência
Kolob Canyon
75

Há várias respostas precisas aqui, mas aqui está o código mais conciso para várias variações diferentes. Para cada variação, a linha superior mostra a sintaxe completa e a parte inferior mostra a sintaxe concisa.

O item (2) é uma forma mais concisa das respostas de Jon Z e manojlds, enquanto o item (1) é equivalente às respostas de vikas368 e buygrush.

  1. Listar objetos FileInfo para todos os arquivos que contêm padrão:

    Get-ChildItem -Recurse filespec | Where-Object { Select-String pattern $_ -Quiet }
    ls -r filespec | ? { sls pattern $_ -q }
    
  2. Listar nomes de arquivos para todos os arquivos que contêm padrão:

    Get-ChildItem -Recurse filespec | Select-String pattern | Select-Object -Unique Path
    ls -r filespec | sls pattern | select -u Path
    
  3. Listar objetos FileInfo para todos os arquivos que não contêm padrão:

    Get-ChildItem -Recurse filespec | Where-Object { !(Select-String pattern $_ -Quiet) }
    ls -r filespec | ? { !(sls pattern $_ -q) }
    
  4. Listar nomes de arquivos para todos os arquivos que não contêm padrão:

    (Get-ChildItem -Recurse filespec | Where-Object { !(Select-String pattern $_ -Quiet) }).FullName
    (ls -r filespec | ? { !(sls pattern $_ -q) }).FullName
    
Michael Sorens
fonte
Além disso, se você está olhando apenas para arquivos que contêm a qualquer padrão, você pode dar-se depois de encontrar a primeira instância usando o -Listparâmetro deSelect-String
KyleMit
Eu gostaria que o OP tivesse feito uma ligeira variação da pergunta para que este fosse o AA. # 1 foi muito útil e é óbvio que @ Michael Sorens groks PS!
CBlaine
20

Isso exibirá o caminho, o nome do arquivo e a linha de conteúdo encontrada que corresponde ao padrão.

Get-ChildItem -Path d:\applications\*config -recurse |  Select-String -Pattern "dummy" 
user5000502
fonte
Se apenas uma linha pode ser adicionado entre os resultados :)
cladelpino
15

Canalize o conteúdo do seu

Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy"

para fl *

Você verá que o caminho já está sendo retornado como uma propriedade dos objetos.

Se você quiser apenas o caminho, use select pathou select -unique pathpara remover duplicatas:

Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy" | select -unique path
manojlds
fonte
1
Graças a vocês, é exatamente isso que estou procurando. Infelizmente, quando existem muitos subdiretórios envolvidos no caminho, o PS corta o caminho absoluto e adiciona três pontos no final da linha, como \ dir1 \ dir2 \ dir3 \ path ... então não sei qual arquivo será retornado . Existe uma maneira de dizer ao PS para ser menos ganancioso com os personagens e se preocupar em mostrar o caminho completo? :) Muito obrigado !
Bluz
3
Você precisa adicionar a -Fileopção Get-ChildItemou acaba com uma cascata interminável de erros ao tentar chamar Get-Contentdiretórios.
9338 RubberDuck
Se você precisar do caminho completo, poderá fazer isso. (Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy").FullNameAs pessoas parecem esquecer que o PowerShell é orientado a objetos; em caso de dúvida, procure um imóvel
Kolob Canyon
10

É assim que eu faria, você não precisa de conteúdo:

ls -r | Select-String dummy | select line,path

ou

ls -r | Select-String dummy | fl *

Para ver quais são as diferentes propriedades ...

Isso é mais rápido. O segundo argumento é -filter:

ls -r . *.bat | select-string netsh
js2010
fonte
2
+1, isso funciona perfeitamente para o meu caso, no entanto, use select Pattern, LineNumber, Filenamepara saída mais concisa. Linha retorna TUDO na linha que contém sua sequência de padrões. Você também pode enviar isso facilmente para um CSV, se desejar.
Protonova 07/07/19
9
Get-ChildItem -r | ? {$_.psiscontainer -eq $false} | ? {gc $_.pspath |select-string -pattern "dummy"}

Isso fornecerá todos os detalhes de todos os arquivos

vikas368
fonte
Totalmente não sabia que -rfuncionava. Achei que você sempre deveria fazer #-Recurse
Kolob Canyon
5

Para manter os detalhes completos do arquivo na matriz resultante, você pode usar uma leve modificação da resposta postada por vikas368 (que não parece funcionar bem com o preenchimento automático do ISE):

Get-ChildItem -Recurse | Where-Object { $_ | Select-String -Pattern "dummy" }

ou em resumo:

ls -r | ?{ $_ | Select-String -Pattern "dummy" }
buygrush
fonte
5

Se você pesquisar em um diretório, poderá fazê-lo:

select-string -Path "c:\temp\*.*" -Pattern "result"  -List | select Path
Esperento57
fonte
4

Isso exibirá uma lista do caminho completo para cada arquivo que contém a string de pesquisa:

foreach ($file in Get-ChildItem | Select-String -pattern "dummy" | Select-Object -Unique path) {$file.path}

Observe que ele não exibe um cabeçalho acima dos resultados e não exibe as linhas de texto que contêm a string de pesquisa. Tudo o que você diz é onde você pode encontrar os arquivos que contêm a string.

Garotinha
fonte
2
Alguma idéia de como exibir o número da linha onde o padrão foi encontrado, junto com o nome do arquivo?
Piotr L
4

Modifiquei uma das respostas acima para me dar um pouco mais de informação. Isso me poupou de uma segunda consulta mais tarde. Era algo assim:

Get-ChildItem `
        -Path "C:\data\path" -Filter "Example*.dat" -recurse | `
    Select-String -pattern "dummy" | `
    Select-Object -Property Path,LineNumber,Line | `
    Export-CSV "C:\ResultFile.csv"

Eu posso especificar o caminho e os curingas de arquivo com essas estruturas, e ele salva o nome do arquivo, o número da linha e a linha relevante em um arquivo de saída.

RenoGreg
fonte
Legal! Obrigado por esta solução adicional :) No entanto, você poderia vincular a resposta em que baseou sua solução e nomear o autor da resposta para dar crédito? Obrigado!
precisa