Repetir arquivos em um diretório usando o PowerShell

243

Como posso alterar o código a seguir para examinar todos os arquivos .log no diretório e não apenas o arquivo?

Eu preciso percorrer todos os arquivos e excluir todas as linhas que não contêm "step4" ou "step9". Atualmente, isso criará um novo arquivo, mas não tenho certeza de como usar o for eachloop aqui (novato).

Os arquivos reais são nomeados assim: 2013 09 03 00_01_29.log . Eu gostaria que os arquivos de saída os substituíssem ou tivessem o mesmo nome, anexado com "out".

$In = "C:\Users\gerhardl\Documents\My Received Files\Test_In.log"
$Out = "C:\Users\gerhardl\Documents\My Received Files\Test_Out.log"
$Files = "C:\Users\gerhardl\Documents\My Received Files\"

Get-Content $In | Where-Object {$_ -match 'step4' -or $_ -match 'step9'} | `
Set-Content $Out
user2725402
fonte

Respostas:

363

Faça uma tentativa:

Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files" -Filter *.log | 
Foreach-Object {
    $content = Get-Content $_.FullName

    #filter and save content to the original file
    $content | Where-Object {$_ -match 'step[49]'} | Set-Content $_.FullName

    #filter and save content to a new file 
    $content | Where-Object {$_ -match 'step[49]'} | Set-Content ($_.BaseName + '_out.log')
}
Shay Levy
fonte
obrigado. A parte BaseName não funciona (versão 1) - mas eu consegui primeiro criar um backup do arquivo completo e depois fazer a alteração no arquivo original.
user2725402
6
Para a v1, você pode usar o seguinte para extrair o nome da base: [io.path] :: GetFileNameWithoutExtension ($ name)
Shay Levy
Se eu substituir BaseNamepor FullName, obtenho o que quero.
M--
77

Para obter o conteúdo de um diretório, você pode usar

$files = Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files\"

Então você pode fazer um loop sobre essa variável também:

for ($i=0; $i -lt $files.Count; $i++) {
    $outfile = $files[$i].FullName + "out" 
    Get-Content $files[$i].FullName | Where-Object { ($_ -match 'step4' -or $_ -match 'step9') } | Set-Content $outfile
}

Uma maneira ainda mais fácil de colocar isso é o foreachloop (graças a @Soapy e @MarkSchultheiss):

foreach ($f in $files){
    $outfile = $f.FullName + "out" 
    Get-Content $f.FullName | Where-Object { ($_ -match 'step4' -or $_ -match 'step9') } | Set-Content $outfile
}
PVitt
fonte
Isso cria um arquivo de saída chamado "out.log". Como posso criar um arquivo de saída separado para cada arquivo de entrada?
user2725402
@ user2725402 Adicionei um arquivo de saída dependente de entrada chamado <nome do arquivo de entrada> fora
PVitt 17/13
não tenho certeza do que estou fazendo de errado, mas isso não está funcionando - agora não recebo arquivos de saída (e sem erros): $files = Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files\" $files | Where-Object { $outFile = $_.Name + "out" Get-Content $_.FullName | Where-Object { $_ -match 'step4' -or $_ -match 'step9' } | Set-Content $outFile }
user2725402
2
Você também pode fazerforeach ($f in Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files\") { ... }
Soapy
1
ou usoForEach ($f in $files){...}
Mark Schultheiss
31

Se você precisar fazer um loop dentro de um diretório recursivamente para um tipo específico de arquivo, use o comando abaixo, que filtra todos os arquivos do doctipo

$fileNames = Get-ChildItem -Path $scriptPath -Recurse -Include *.doc

Se você precisar fazer a filtragem em vários tipos, use o comando abaixo.

$fileNames = Get-ChildItem -Path $scriptPath -Recurse -Include *.doc,*.pdf

Agora, a $fileNamesvariável atua como uma matriz da qual você pode fazer um loop e aplicar sua lógica de negócios.

Sarath Avanavu
fonte
O que me incomodou foi a omissão de arquivos ocultos e / ou do sistema. Para vê-los também, você deve usar o -Forceparâmetro Get-ChildItem. Consulte o documento em docs.microsoft.com/en-us/powershell/module/… .
til_b
-6

Outras respostas são ótimas, só quero adicionar ... uma abordagem diferente utilizável no PowerShell: Instale os utilitários GNUWin32 e use grep para exibir as linhas / redirecionar a saída para o arquivo http://gnuwin32.sourceforge.net/

Isso substitui o novo arquivo sempre:

grep "step[49]" logIn.log > logOut.log 

Isso anexa a saída do log, caso você substitua o arquivo logIn e deseje manter os dados:

grep "step[49]" logIn.log >> logOut.log 

Nota: para poder usar os utilitários GNUWin32 globalmente, você precisa adicionar a pasta bin ao caminho do sistema.

user1628658
fonte
18
Esta questão foi etiquetada como PowerShell, não Unix
SteveC
2
Sim. Obviamente. Minha opinião foi bastante simples: você pode usar os utilitários GNUWin32 no Windows, portanto, você pode usar as ferramentas * nix no Powershell facilmente. Trabalho. Ninguém nunca disse que a resposta tinha que ser totalmente nativa do Powershell. E mesmo se o fizessem, você ainda pode ligar para o Win32 Utils diretamente do Powershell. AFAIK usando o que está disponível e compatível não é realmente uma coisa ruim.
usar o seguinte comando
2
Eu teria editado meu comentário anterior, mas ultrapassei o limite de 5 minutos: SteveC: Você está dizendo que a incorporação de ferramentas GNU que funcionam bem no Windows está de alguma forma desafiando o Powershell? Isso é uma coisa. Entendo que resolver isso exclusivamente no Powershell pode ser mais produtivo a curto prazo. A longo prazo, expandir as possibilidades tem realmente mais mérito. Você adiciona mais opções e trabalha totalmente no Windows e no Powershell sem nenhum emulador de Linux como o Cygwin. Então, enquanto eu entendo sua reserva, eu discordo.
usar o seguinte comando
5
A pergunta era sobre procurar no PowerShell, não na infinidade de outros idiomas que poderiam ser usados.
SteveC
1
As respostas devem ser feitas para a pergunta. Essa pergunta era explícita, pois queria a resposta no PowerShell. Sua resposta foi instalar algo e usá-lo. Você poderia ter sugerido a instalação do Ruby, etc. #
SteveC 13/12