Pętlę plików w katalogu za pomocą PowerShell

243

Jak mogę zmienić poniższy kod, aby wyświetlić wszystkie pliki .log w katalogu, a nie tylko jeden plik?

Muszę przejść przez wszystkie pliki i usunąć wszystkie wiersze, które nie zawierają „step4” lub „step9”. Obecnie utworzy to nowy plik, ale nie jestem pewien, jak użyć for eachtutaj pętli (nowicjusz).

Rzeczywiste pliki mają następujące nazwy: 2013 09 03 00_01_29.log . Chciałbym, aby pliki wyjściowe albo je nadpisały, albo dodały taką samą nazwę, jak „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
użytkownik2725402
źródło

Odpowiedzi:

363

Wypróbuj to:

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
źródło
dzięki. Część BaseName nie działa (wersja 1) - ale udało mi się najpierw utworzyć kopię zapasową pełnego pliku, a następnie wprowadzić zmiany w oryginalnym pliku.
user2725402
6
W przypadku wersji 1 można użyć następującego polecenia, aby wyodrębnić nazwę podstawową: [io.path] :: GetFileNameWithoutExtension ($ name)
Shay Levy
Jeśli mogę wymienić BaseNamez FullNamedostanę co chcę.
M--
78

Aby uzyskać zawartość katalogu, możesz użyć

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

Następnie możesz również zapętlić tę zmienną:

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
}

Jeszcze łatwiejszym sposobem na umieszczenie tego jest foreachpętla (dzięki @Soapy i @MarkSchultheiss):

foreach ($f in $files){
    $outfile = $f.FullName + "out" 
    Get-Content $f.FullName | Where-Object { ($_ -match 'step4' -or $_ -match 'step9') } | Set-Content $outfile
}
PVitt
źródło
Spowoduje to utworzenie jednego pliku wyjściowego o nazwie „out.log”. Jak mogę utworzyć osobny plik wyjściowy dla każdego pliku wejściowego?
user2725402
@ user2725402 Dodałem plik wyjściowy zależny od wejścia o nazwie <nazwa pliku wejściowego> out
PVitt,
nie jestem pewien, co robię źle, ale to nie działa - teraz nie otrzymuję plików wyjściowych (i żadnych błędów): $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
Możesz także zrobićforeach ($f in Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files\") { ... }
Soapy
1
lub użyjForEach ($f in $files){...}
Mark Schultheiss
31

Jeśli chcesz zapętlić się wewnątrz katalogu rekurencyjnie dla określonego rodzaju pliku, użyj poniższego polecenia, które filtruje wszystkie pliki doctypu pliku

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

Jeśli musisz wykonać filtrację na wielu typach, użyj poniższego polecenia.

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

Teraz $fileNameszmienna działa jak tablica, z której można zapętlić i zastosować logikę biznesową.

Sarath Avanavu
źródło
To, co mnie wkurzyło, to pominięcie ukrytych i / lub plików systemowych. Aby je również zobaczyć, musisz użyć -Forceparametru Get-ChildItem. Zobacz dokumentację na docs.microsoft.com/en-us/powershell/module/… .
til_b
-6

Inne odpowiedzi są świetne, chcę tylko dodać ... inne podejście przydatne w PowerShell: zainstaluj narzędzia GNUWin32 i użyj grep, aby wyświetlić linie / przekierować dane wyjściowe do pliku http://gnuwin32.sourceforge.net/

Spowoduje to zastąpienie nowego pliku za każdym razem:

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

To dołącza dane wyjściowe dziennika, na wypadek, gdyby nadpisałeś plik logIn i chcesz zachować dane:

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

Uwaga: aby móc korzystać z narzędzi GNUWin32 na całym świecie, musisz dodać folder bin do ścieżki systemowej.

użytkownik1628658
źródło
18
To pytanie zostało oznaczone jako PowerShell, a nie Unix
SteveC
2
Tak. Oczywiście. Moje zdanie było dość proste: możesz używać narzędzi GNUWin32 w systemie Windows, dzięki czemu możesz łatwo używać narzędzi * nix w Powershell. Pracuje. Nikt nigdy nie powiedział, że odpowiedź musi być całkowicie natywna dla Powershell. A nawet jeśli tak, nadal możesz wywołać Win32 Utils bezpośrednio z Powershell. AFAIK korzystający z tego, co jest dostępne i kompatybilne, nie jest wcale taki zły.
user1628658
2
Zredagowałbym mój poprzedni komentarz, ale przekroczyłem limit 5 minut: SteveC: Czy mówisz, że włączenie narzędzi GNU, które działają dobrze w systemie Windows, w jakiś sposób przeczy Powershellowi? To jedno. Rozumiem, że wypracowanie tego wyłącznie w PowerShell może być bardziej produktywne w krótkim okresie. W dłuższej perspektywie poszerzanie możliwości ma więcej zalet. Dodajesz więcej opcji i pracujesz całkowicie w systemie Windows i Powershell bez żadnych emulatorów Linuksa, takich jak Cygwin. Tak więc, chociaż rozumiem twoją rezerwację, nie zgadzam się.
user1628658,
5
Pytanie dotyczyło korzystania z PowerShell, a nie wielu innych języków, których można by użyć.
SteveC,
1
Odpowiedzi mają być na pytanie. To pytanie było jednoznaczne, ponieważ wymagało odpowiedzi w programie PowerShell. Twoja odpowiedź brzmi: zainstaluj i użyj tego. Mogłeś zasugerować instalację Ruby itp.
SteveC,