PowerShell - Dosyadaki Dizeyi Bul [4 Yol]


1. Genel Bakış

Metin dosyalarındaki dizeleri aramak, PowerShell'de günlük dosyası analizi ve yapılandırma dosyası aramaları gibi senaryolarda kullanılan yaygın bir görevdir. Bu makalede, hem büyük/küçük harfe duyarlı hem de büyük/küçük harfe duyarlı olmayan yaklaşımlar dahil, dosyalarda dize bulmaya yönelik çeşitli yöntemler araştırılmaktadır.

2. Problem İfadesine Giriş

server.log adında bir günlük dosyası düşünelim:

Server.log'un içeriği:

2023-11-24 10:00:00 INFO Starting server process
2023-11-24 10:00:05 ERROR Failed to bind to port 8080
2023-11-24 10:00:10 INFO Server listening on port 9090
2023-11-24 10:01:00 ERROR Database connection timeout

Amacımız bu dosyada Error dizisinin oluşumlarını bulmaktır.
Beklenen çıktı "Hata" içeren satırlardır.

Beklenen Çıktı:

2023-11-24 10:00:05 ERROR Failed to bind to port 8080
2023-11-24 10:01:00 ERROR Database connection timeout

Ek olarak, hem büyük/küçük harfe duyarlı hem de büyük/küçük harfe duyarlı olmayan arama yöntemlerini inceleyeceğiz.

3. Get-Content ve Select-String Cmdlet'lerini Kullanma

Bu yöntem, Get-Content cmdlet'ini kullanarak dosya içeriğinin okunmasını ve dosyada gerekli dizenin aranması için çıktısının Select-Stirng cmdlet'ine aktarılmasını içerir.

Get-Content ve Select-String Cmdlet'lerini kullanma:

Get-Content server.log | Select-String _Pattern "Error"

Açıklama:
Get-Content server.log: Server.log içeriğini okur.
|: Verileri yönlendirir Get-Content komutunun Select-String'e çıktısı.
Select-String -Pattern "Error": Şunu arar: Kanaldan alınan girişte "Hata" dizisi.

Bu komut, server.log dosyasındaki Error kalıbını arar ve Get-Content dosyanın tamamını belleğe okuduğu için büyük dosyalarda daha yavaş olabilir. Varsayılan olarak büyük/küçük harfe duyarlı değildir. Büyük/küçük harfe duyarlı hale getirmek için -CaseSensitive flagını kullanabiliriz.

Get-Content ve Select-String Cmdlet'lerini kullanma:

Get-Content server.log | Select-String _Pattern "Error" -CaseSensitive

4. Select-String Cmdlet'ini Doğrudan Kullanma

Diğer bir yöntem ise Select-String Cmdlet'ini Doğrudan kullanmaktır.

Select-String Cmdlet'ini Kullanma:

Select-String -Path server.log -Pattern "Error"

Açıklama:
Select-String: Dize araması için kullanılan cmdlet.
-Path sunucusu.log: dosya yolu.
-Desen "Hata": Aranacak dize modelini tanımlar.

Bu komutun çıktısı şöyle olacaktır:

Çıkış:

server.log.txt:2:2023-11-24 10:00:05 ERROR Failed to bind to port 8080
server.log.txt:4:2023-11-24 10:01:00 ERROR Database connection timeout

Dosya adını ve satır numarasını çıktının dışında bırakmak için aşağıdaki komutu kullanabiliriz:

Select-String Cmdlet'ini Kullanma:

Select-String -Path server.log -Pattern "Error" -SimpleMatch | ForEach-Object { $_.Line }

Yukarıdaki komutu daha ayrıntılı olarak anlayalım:

| ForEach-Object { $_.Line : Bu işlem hattı, $_ olarak temsil edilen Select-String tarafından oluşturulan her eşleşme nesnesini alır ve yalnızca <'yi çıkarır..Line özelliği, satırın gerçek metnini içerir.

Şimdi beklenen çıktı aşağıdaki gibi olacaktır:

Beklenen Çıktı:

2023-11-24 10:00:05 ERROR Failed to bind to port 8080
2023-11-24 10:01:00 ERROR Database connection timeout

Bu yaklaşım, sonuçların dosya adını ve satır numarasını çıkararak çıktının yalnızca arama dizesini içeren satırların metnini içermesini sağlar.

String içerisinde desen ararken normal ifade ile Select-String komutunu da kullanabiliriz.

Diyelim ki Error dizesinin ardından sayının gelmesi gereken desen aramak istediğimizi varsayalım.

Select-String cmdlet'ini kullanma:

Select-String -Path server.log -Pattern 'Error\d+' -AllMatches

Bu komut, Error ve ardından sayılar içeren satırları görüntüler. -AllMatches bayrağı dışında yukarıdaki komuta benzer. AllMatches belirli bir düzenin tüm eşleşmelerini döndürür.

Bu yöntem ayrıca varsayılan olarak büyük/küçük harfe duyarlı değildir. Büyük/küçük harfe duyarlı hale getirmek için -CaseSensitive flagını kullanabiliriz.

Get-Content ve Select-String Cmdlet'lerini kullanma:

Select-String -Path server.log -Pattern "Error" -CaseSensitive -SimpleMatch | ForEach-Object { $_.Line }

5. Get-Content'in -ReadCount Parametresi ve -Match Operatörü ile Kullanımı

Bu yaklaşım büyük dosyalarla uğraşırken kullanılabilir. Büyük dosyaları parçalar halinde işleyerek okumayı optimize eder.

Örnek yardımıyla görelim:

GetContent'i -Match operatörüyle kullanma:

(Get-Content server.log -ReadCount 1000) -match "Error"

(Get-Content server.log -ReadCount 1000): Belleği parçalar halinde, tek seferde 1000 satır okur.
-eşleşme "Hata": Dosya parçalarında "Hata" kalıbı.

Basit bir ifadeyle, Get-Content dosyanın parçalarını okuduktan sonra -match "Error" operatörü uygulanır. Bu operatör her bir öbeği filtreler ve yalnızca "Hata" dizesini içeren satırları döndürür. Eşleşme varsayılan olarak büyük/küçük harfe duyarlı değildir.

Bu yöntem büyük dosyalar için daha hızlı ve hafıza açısından verimli olabilir.

-match varsayılan olarak büyük/küçük harfe duyarlı olmadığından -cmatch operatörünü büyük/küçük harfe duyarlı arama için kullanabiliriz.

6. foreach Döngüsünü if Block ile Kullanmak

Diğer bir yöntem ise if bloğu ile foreach döngüsünü kullanmaktır. Bu yaklaşım yavaştır ancak her satırı ayrı ayrı işlerken kullanışlıdır.

Örnek yardımıyla görelim:

Foreach döngüsünü kullanma:

foreach ($line in Get-Content server.log) { if ($line -match "Error") { $line } }

Açıklama:

foreach (Get-Content sunucusu.log'daki $satır): Dosyanın her satırında yinelenir.
if ($line -match "Error") { $line >: Satırın "Error içerip içermediğini kontrol eder ve doğruysa çıktısını verir.

Yani her satırı yinelerken, eğer satırda Kalıp Hatası bulunuyorsa, onu yazdıracaktır.

Yine burada da büyük/küçük harfe duyarlı arama için -cmatch operatörünü kullanabiliriz.

7. Dosyada Birden Fazla Desen Arama

Senaryo üzerinde çalışırken çoğu zaman tek bir kalıp yerine çoklu kalıplara göre arama yapmamız gereken durumlar vardır.

Bunu yapmanın birden fazla yolu var. Örnekler yardımıyla görelim:

Select-String çoklu desenleri:

Select-String -Path server.log -Pattern "Error", "Warning", "Failed"

Bu komut, server.log'da listelenen kalıplardan herhangi birini ("Hata", "Uyarı", "Başarısız") arar.

Bunu normal ifadeler kullanarak birleştirmek.

Select-String çoklu desenleri:

Select-String -Path server.log -Pattern "Error|Warning|Failed

-ReadCount ile İçerik Alın:

(Get-Content server.log -ReadCount 1000) -match "Error|Warning|Failed"

Select-String'i bir dizi desenle kullanma

Select-String çoklu desenleri:

$patterns = "Error", "Warning"; Select-String -Path server.log -Pattern $patterns

Gelişmiş kalıp eşleştirme için komut dosyası bloklarını kullanma

Komut dosyası bloklarını kullanma:

Get-Content server.log | Where-Object { $_ -match "Error" -or $_ -match "Warning" 

8. Dizin ve Alt Dizinlerdeki Dizeleri Arama

İstenilen metin için birden fazla dosyanın kapsamlı bir şekilde taranmasını sağlayarak yalnızca tek bir dosyada değil, tüm bir dizinde ve alt dizinlerinde belirli dizeleri nasıl arayacağınızı keşfedelim.

Bu, Get-ChildItem ve Select-String kombinasyonunu kullanıyor olabilir.

Dizin ve Alt Dizinlerdeki Dizeleri Arama:

Get-ChildItem -Path C:\Logs -Recurse | Select-String -Pattern "Error"

Get-ChildItem -Path C:\Logs -Recurse: C:\Logs ve alt dizinlerindeki tüm dosyaları alır. Select-String'e aktarıldığında, her dosyada belirtilen modeli arar.

Şimdi sadece .log uzantılı dosyalarda desen aramak istersek ne olur? Bu, -Include bayrağı kullanılarak gerçekleştirilebilir.

Dizin ve Alt Dizinlerdeki Dizeleri Arama:

Get-ChildItem -Path C:\Logs -Recurse -Include *.log | Select-String -Pattern "Error"

Bu komut öncekine benzer ancak aramayı belirli bir uzantıya sahip dosyalarla (ör. .log) sınırlandırır. Karışık dosya türlerine sahip dizinler arasında arama yaparken etkilidir.

9. Performans Karşılaştırması

En iyisini seçebilmemiz için her yöntemin ne kadar hızlı çalıştığını test etmek önemlidir.

1 milyon satırlık büyük bir server.log girdisi oluşturacağız ve bunun üzerindeki her çözümü, dosyadaki "Hata" kalıbını arayacak şekilde test edeceğiz.
Performanslarını karşılaştırın, Measure-Command cmdlet'ini kullanacağız. Her yöntemin performansını ölçen komut dosyası:

Performans ölçüsü:

# Define the file and search pattern
$filePath = "server.log"
$searchPattern = "Error"

# Method 1: Using Get-Content and Select-String
$method1 = {
    Get-Content $filePath | Select-String $searchPattern
}

# Method 2: Using Select-String Directly
$method2 = {
    Select-String -Path $filePath -Pattern $searchPattern -SimpleMatch | ForEach-Object { $_.Line }
}

# Method 3: Get-Content with -ReadCount and -Match
$method3 = {
    (Get-Content $filePath -ReadCount 1000) -match $searchPattern
}

# Method 4: Using foreach Loop
$method4 = {
    foreach ($line in Get-Content $filePath) { if ($line -match $searchPattern) { $line } }
}

# Measure and output the time for each method
"Method 1 Time: $(Measure-Command $method1).TotalMilliseconds ms"
"Method 2 Time: $(Measure-Command $method2).TotalMilliseconds ms"
"Method 3 Time: $(Measure-Command $method3).TotalMilliseconds ms"
"Method 4 Time: $(Measure-Command $method4).TotalMilliseconds ms"

Şimdi test sonuçlarına bakalım:

test sonuçları:

Method 1 Time: 00:00:20.2374519.TotalMilliseconds ms
Method 2 Time: 00:00:05.2277779.TotalMilliseconds ms
Method 3 Time: 00:00:03.6214583.TotalMilliseconds ms
Method 4 Time: 00:01:10.4835464.TotalMilliseconds ms

Her yöntemin çıktı sürelerine göre:

Yöntem 1 (Get-Content ve Select-String Kullanımı): Yaklaşık 20,24 saniye sürdü.
Yöntem 2 (Doğrudan Select-String Kullanımı): Yaklaşık 5,23 saniye sürdü .
Yöntem 3 (Get-Content'i -ReadCount ve -Match ile kullanmak): Yalnızca 3,62 saniye sürerek en hızlısıydı.
Yöntem 4 (foreach kullanmak) Döngü): Yaklaşık 70,48 saniye sürerek en yavaş olanıydı.

10. Sonuç

Özetle, farklı PowerShell dize arama yöntemlerinin performansı büyük ölçüde farklılık gösterir. Dosyaları parçalar halinde okuyan en hızlı yöntem, hızı ve verimliliği nedeniyle büyük dosyalar için idealdir. Doğrudan desen eşleştirme yöntemleri, basit aramalar için basitlik ve hız arasında iyi bir denge sunar. Bununla birlikte, her satırı ayrı ayrı işleyen en yavaş yaklaşım, ayrıntılı analiz için veya aramanın kapsamlılığının hız ihtiyacından daha ağır bastığı daha küçük dosyalarla çalışırken en iyisidir. Yöntem seçimi, dosya boyutu ve arama karmaşıklığı dikkate alınarak görevin özel ihtiyaçlarına göre yapılmalıdır.

İlgili makaleler