Lặp lại các tệp trong một thư mục bằng PowerShell


243

Làm cách nào để thay đổi mã sau đây để xem tất cả các tệp .log trong thư mục chứ không chỉ một tệp?

Tôi cần lặp qua tất cả các tệp và xóa tất cả các dòng không chứa "step4" hoặc "step9". Hiện tại điều này sẽ tạo một tệp mới, nhưng tôi không chắc cách sử dụng for eachvòng lặp ở đây (newbie).

Các tập tin thực tế được đặt tên như thế này: 2013 09 03 00_01_29.log . Tôi muốn các tệp đầu ra ghi đè lên chúng hoặc có tên CÙNG, được gắn thêm "ngoài".

$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

Câu trả lời:


363

Hãy thử xem:

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')
}

cảm ơn. Phần BaseName không hoạt động (phiên bản 1) - nhưng trước tiên tôi đã quản lý bằng cách tạo bản sao lưu của tệp đầy đủ sau đó thực hiện thay đổi thành tệp gốc.
dùng2725402

6
Đối với v1, bạn có thể sử dụng cách sau để trích xuất tên cơ sở: [io.path] :: GetFileNameWithoutExtension ($ name)
Shay Levy

Nếu tôi thay thế BaseNamebằng FullNametôi có được những gì tôi muốn.
M--

77

Để có được nội dung của một thư mục bạn có thể sử dụng

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

Sau đó, bạn cũng có thể lặp qua biến này:

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
}

Một cách thậm chí dễ dàng hơn để đặt điều này là foreachvòng lặp (nhờ @Soacco và @MarkSchultheiss):

foreach ($f in $files){
    $outfile = $f.FullName + "out" 
    Get-Content $f.FullName | Where-Object { ($_ -match 'step4' -or $_ -match 'step9') } | Set-Content $outfile
}

Điều này tạo ra một tệp đầu ra có tên "out.log". Làm cách nào để tạo một tệp đầu ra riêng cho mỗi tệp đầu vào?
dùng2725402

@ user2725402 Tôi đã thêm một tệp đầu ra phụ thuộc đầu vào được đặt tên <tên tệp đầu vào> ra
PVitt

không chắc chắn những gì tôi đã làm sai nhưng điều này không hoạt động - Bây giờ tôi không nhận được tệp đầu ra (và không có lỗi): $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
Bạn cũng có thể làmforeach ($f in Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files\") { ... }
Xà phòng

1
hoặc sử dụngForEach ($f in $files){...}
Mark Schultheiss

31

Nếu bạn cần lặp bên trong một thư mục đệ quy cho một loại tệp cụ thể, hãy sử dụng lệnh bên dưới, để lọc tất cả các tệp thuộc docloại tệp

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

Nếu bạn cần thực hiện lọc trên nhiều loại, hãy sử dụng lệnh dưới đây.

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

Bây giờ $fileNamesbiến hoạt động như một mảng mà từ đó bạn có thể lặp và áp dụng logic kinh doanh của mình.


Điều khiến tôi bận tâm là thiếu sót của các tập tin hệ thống và / hoặc ẩn. Để xem chúng, bạn phải sử dụng -Forcetham số cho Get-ChildItem. Xem tài liệu của nó tại docs.microsoft.com/en-us/powershell/module/ .
til_b

-6

Các câu trả lời khác rất hay, tôi chỉ muốn thêm ... một cách tiếp cận khác có thể sử dụng được trong PowerShell: Cài đặt các tiện ích GNUWin32 và sử dụng grep để xem các dòng / chuyển hướng đầu ra sang tệp http://gnuwin32.sourceforge.net/

Điều này ghi đè lên tệp mới mỗi lần:

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

Điều này sẽ nối đầu ra nhật ký, trong trường hợp bạn ghi đè lên tệp logIn và muốn giữ dữ liệu:

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

Lưu ý: để có thể sử dụng các tiện ích GNUWin32 trên toàn cầu, bạn phải thêm thư mục bin vào đường dẫn hệ thống của mình.


18
Câu hỏi này được gắn thẻ là PowerShell, không phải Unix
SteveC

2
Đúng. Chắc chắn. Cách làm của tôi khá đơn giản: Bạn có thể sử dụng các tiện ích GNUWin32 trong Windows do đó bạn có thể sử dụng các công cụ * nix trong Powershell một cách dễ dàng. Làm. Không ai từng nói, rằng câu trả lời phải hoàn toàn có nguồn gốc từ Powershell. Và ngay cả khi họ đã làm, bạn vẫn có thể gọi Win32 Utils trực tiếp từ Powershell. AFAIK sử dụng bất cứ thứ gì có sẵn và tương thích không thực sự là một điều xấu.
dùng1628658

2
Tôi đã chỉnh sửa nhận xét trước đây của mình, nhưng tôi đã vượt qua giới hạn 5 phút: SteveC: Bạn có nói rằng việc kết hợp các công cụ GNU hoạt động tốt trong Windows bằng cách nào đó đã thách thức Powershell? Đó là một điều. Tôi hiểu rằng làm việc này hoàn toàn trong Powershell có thể sẽ hiệu quả hơn trong ngắn hạn. Trong dài hạn mở rộng các khả năng thực sự có nhiều công đức. Bạn thêm nhiều tùy chọn hơn và đang hoạt động hoàn toàn trong Windows và Powershell mà không cần bất kỳ trình giả lập Linux nào như Cygwin. Vì vậy, trong khi tôi hiểu đặt phòng của bạn, tôi không đồng ý.
dùng1628658

5
Câu hỏi là về việc tìm kiếm trong PowerShell, không phải vô số ngôn ngữ khác có thể được sử dụng.
SteveC

1
Câu trả lời có nghĩa là câu hỏi. Câu hỏi này rõ ràng ở chỗ nó muốn câu trả lời trong PowerShell. Câu trả lời của bạn đã được cài đặt một cái gì đó và sử dụng nó. Bạn có thể đã đề nghị cài đặt Ruby, v.v.
SteveC
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.