pcregrep ile Perl Uyumlu Regex: Çok Satırlı Desen Eşleştirme ve Gelişmiş Arama Teknikleri
Yıllarca grep ile idare ettim, itiraf edeyim. Standart regex yeterliydi çoğu zaman, kimse de şikayet etmiyordu. Ta ki bir gün production log dosyalarında çok satırlı hata bloklarını ayıklamam gerekene kadar. O gün pcregrep ile tanıştım ve hayatım bir daha eskisi gibi olmadı. Biraz dramatik kulağa geliyor, biliyorum, ama metin işleme dünyasında Perl uyumlu regex’in ne anlama geldiğini bir kez yaşayınca anlıyorsunuz.
pcregrep Nedir ve Neden Önemsememiz Gerekir
pcregrep, PCRE (Perl Compatible Regular Expressions) kütüphanesini kullanan, grepin daha güçlü bir alternatifidir. Standart grep POSIX regex kullanır, GNU grep ise -P flag’i ile sınırlı düzeyde PCRE desteği sunar. Ama pcregrep baştan aşağı PCRE için tasarlanmıştır ve özellikle çok satırlı eşleştirme konusunda rakipsizdir.
Temel fark şurada: standart grep satır bazlı çalışır. Her satırı bağımsız bir birim olarak değerlendirir. pcregrep ise -M flag’i ile birden fazla satırı tek bir blok olarak ele alabilir. Bu, özellikle stack trace’ler, XML/JSON blokları ve çok satırlı log girişleri için çığır açan bir özelliktir.
Kurulum oldukça basit:
# Debian/Ubuntu
sudo apt-get install pcregrep
# RHEL/CentOS/Rocky Linux
sudo yum install pcre-tools
# veya
sudo dnf install pcre-tools
# macOS (Homebrew)
brew install pcre
Kurulumu doğrulamak için:
pcregrep --version
# pcregrep 8.45 2021-06-15
Temel Kullanım ve Parametre Rehberi
Önce temel parametreleri tanıyalım, sonra gerçek senaryolara geçeceğiz.
-M veya –multiline: Çok satırlı mod, . karakterinin newline’ı da eşleştirmesini sağlar -i: Büyük/küçük harf duyarsız arama -n: Satır numaralarını göster -l: Sadece eşleşen dosya adlarını listele -L: Eşleşme olmayan dosyaları listele -r: Dizinleri özyinelemeli tara -v: Eşleşmeyen satırları göster (invert match) -c: Eşleşme sayısını göster -o: Sadece eşleşen kısmı göster -A n: Eşleşmeden sonra n satır göster -B n: Eşleşmeden önce n satır göster -C n: Eşleşmenin hem öncesinde hem sonrasında n satır göster –color: Eşleşmeleri renkli göster -e pattern: Birden fazla desen belirlemek için kullanılır -f dosya: Desenleri dosyadan oku –om-separator: -o ile birden fazla eşleşme arasına ayraç koy
Basit bir örnekle başlayalım:
# Standart grep ile aynı temel kullanım
pcregrep "ERROR" /var/log/syslog
# Büyük/küçük harf duyarsız, satır numaralı
pcregrep -in "error|warning" /var/log/application.log
# Birden fazla desen
pcregrep -e "OutOfMemory" -e "StackOverflow" /var/log/app.log
Çok Satırlı Eşleştirme: Asıl Güç Burada
pcregrepin standart araçlardan ayrıldığı en kritik nokta burası. -M flag’i ile satır sınırlarını aşan desenleri yakalayabilirsiniz.
Diyelim ki şöyle bir Java stack trace’i var:
2024-01-15 14:23:11 ERROR Application crashed
java.lang.NullPointerException: Cannot invoke method
at com.example.UserService.getUser(UserService.java:45)
at com.example.Controller.handle(Controller.java:78)
2024-01-15 14:23:12 INFO Server still running
Bu bloğu bir bütün olarak yakalamak için:
# -M ile çok satırlı mod
pcregrep -M "ERROR.*njava.lang." /var/log/app.log
# Daha geniş bir blok yakalamak için
pcregrep -M "ERROR.*n(.*n){1,10}.*at com.example." /var/log/app.log
Gerçek hayattan bir senaryo: Nginx access log’larında belirli bir IP’nin art arda 5xx hatası aldığı blokları tespit etmeniz gerekiyor. Bu durumda çok satırlı eşleştirme ile kombinasyon yapabilirsiniz.
# Belirli bir IP'den gelen 5xx hatalarını çok satırlı bloklar halinde yakala
pcregrep -M "192.168.1.100.*" 5[0-9]{2}" /var/log/nginx/access.log
PCRE’nin Özel Gücü: Lookahead ve Lookbehind
Standart grepte olmayan ama pcregrepte kullanabileceğiniz en değerli özelliklerden biri lookahead (ileri bakış) ve lookbehind (geri bakış) assertions’larıdır. Eşleşmenin kendisini değil, etrafındaki bağlamı kontrol ederler.
Lookahead örnekleri:
# "password" kelimesinden sonra ":" gelenleri bul (password: kısmını yakala ama ":" gösterme)
pcregrep -o "password(?=:)" config.txt
# "ERROR" ile başlayan ama "timeout" içermeyen satırları bul
pcregrep "ERROR(?!.*timeout)" /var/log/app.log
# Sayıdan önce "port" kelimesi gelenler
pcregrep -o "(?<=port )d+" nginx.conf
Lookbehind örnekleri:
# "user=" den sonra gelen kullanıcı adını çıkar
pcregrep -o "(?<=user=)[a-zA-Z0-9_]+" auth.log
# Fiyat işaretinden sonra gelen rakamları bul
pcregrep -o "(?<=$)d+.d{2}" invoices.txt
Gerçek dünya senaryosu: Apache log’larından sadece authenticated kullanıcıların yaptığı 404 isteklerini çıkarmak istiyorsunuz.
# Auth başarılı olmuş (200 auth response geçmiş) ama 404 alan istekler
pcregrep "(?<=" )404(?= )" /var/log/apache2/access.log |
pcregrep -v "(?<=" 401 )"
Named Capture Groups ile Yapılandırılmış Veri Çıkarma
PCRE’nin bir diğer süper özelliği named capture groups. Log’lardan yapılandırılmış veri çıkarırken bu özellik son derece işe yarar.
# IP adresi ve HTTP status kodunu named group ile yakala
pcregrep -o "(?P<ip>d{1,3}.d{1,3}.d{1,3}.d{1,3}).*(?P<status>[45]d{2})"
/var/log/nginx/access.log
Bir script içinde kullanımı daha da anlamlı hale gelir. Örneğin bir monitoring scripti yazıyorsunuz:
#!/bin/bash
# Son 1 saatin kritik hatalarını çıkar ve raporla
LOG_FILE="/var/log/application.log"
REPORT_FILE="/tmp/error_report_$(date +%Y%m%d_%H).txt"
echo "=== Hata Raporu ===" > "$REPORT_FILE"
echo "Tarih: $(date)" >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"
# PCRE ile karmaşık desenleri yakala
pcregrep -n
"(?i)(critical|fatal|error).*(?:exception|failure|crash)"
"$LOG_FILE" >> "$REPORT_FILE"
# Eşleşme sayısını da raporla
ERROR_COUNT=$(pcregrep -c
"(?i)(critical|fatal|error).*(?:exception|failure|crash)"
"$LOG_FILE")
echo "" >> "$REPORT_FILE"
echo "Toplam kritik hata sayısı: $ERROR_COUNT" >> "$REPORT_FILE"
# Eğer 10'dan fazla hata varsa uyarı gönder
if [ "$ERROR_COUNT" -gt 10 ]; then
echo "KRİTİK: Son 1 saatte $ERROR_COUNT hata tespit edildi!" |
mail -s "Alarm: Yüksek Hata Oranı" [email protected]
fi
echo "Rapor oluşturuldu: $REPORT_FILE"
Özyinelemeli Arama ve Dosya Filtreleme
Büyük kod tabanlarında veya log dizinlerinde çalışırken özyinelemeli arama vazgeçilmez olur.
# Tüm Python dosyalarında güvensiz fonksiyon kullanımını tara
pcregrep -r --include="*.py"
"(?i)(eval|exec|pickle.loads|subprocess.call.*shell=True)"
/opt/myapp/
# Config dosyalarında şifrelenmemiş credential'ları bul
pcregrep -r --include="*.conf" --include="*.yaml" --include="*.yml"
"(?i)(password|passwd|secret|api_key)s*[:=]s*['"]?[^'"s]{8,}"
/etc/ 2>/dev/null
# Belirli dosyaları hariç tutarak arama
pcregrep -r --exclude="*.log.gz" --exclude="*.bak"
"TODO|FIXME|HACK"
/var/www/html/
Log rotasyon yapıldıktan sonra bile eski dosyalarda arama yapmak gerekebilir:
# Sıkıştırılmış log'ları da dahil ederek ara
# (zgrep ile birlikte kullanım)
for logfile in /var/log/nginx/access.log*; do
if [[ "$logfile" == *.gz ]]; then
zcat "$logfile" | pcregrep "(?i)sql.*injection|union.*select"
else
pcregrep "(?i)sql.*injection|union.*select" "$logfile"
fi
done
Gerçek Dünya Senaryosu: Güvenlik Denetimi
Bir güvenlik denetimi senaryosu yaşadım geçen yıl. Web uygulama log’larında SQL injection girişimlerini tespit etmem gerekiyordu. Standart grep desenleri çok fazla false positive üretiyordu. pcregrep ile yazdığım desen hem daha hassas hem daha kapsamlıydı:
# SQL Injection pattern - gelişmiş PCRE deseni
pcregrep -i
"(?:unions+(?:alls+)?select|selects+.*s+from|inserts+into|drops+table|exec(?:ute)?s*(|xp_cmdshell)"
/var/log/apache2/access.log |
pcregrep -v "(?:googlebot|bingbot|health.?check)" |
awk '{print $1}' | sort | uniq -c | sort -rn | head -20
Bununla da kalmayıp, şüpheli IP’lerin davranış örüntüsünü çok satırlı analizle inceledim:
#!/bin/bash
# Şüpheli IP davranış analizi
SUSPICIOUS_IP="$1"
LOG_FILE="/var/log/apache2/access.log"
echo "IP: $SUSPICIOUS_IP için davranış analizi"
echo "============================================"
echo -e "n[1] Toplam istek sayısı:"
pcregrep "^$SUSPICIOUS_IP " "$LOG_FILE" | wc -l
echo -e "n[2] HTTP metod dağılımı:"
pcregrep -o ""(?:GET|POST|PUT|DELETE|OPTIONS|PATCH)[^"]*""
<(pcregrep "^$SUSPICIOUS_IP " "$LOG_FILE") |
grep -oP "^"[A-Z]+" | sort | uniq -c | sort -rn
echo -e "n[3] 4xx ve 5xx hatalar:"
pcregrep "^$SUSPICIOUS_IP .*" [45][0-9]{2} " "$LOG_FILE" | wc -l
echo -e "n[4] Şüpheli payload'lar:"
pcregrep -i "^$SUSPICIOUS_IP .*(?:etc/passwd|/proc/self|../|<script|javascript:)"
"$LOG_FILE"
Desenlerinizi Dosyadan Okumak
Büyük bir desen koleksiyonunuz varsa, bunları doğrudan komut satırına yazmak hem pratik değil hem de hata oranını artırır. -f parametresi ile desenleri dosyadan okuyabilirsiniz:
# patterns.txt dosyası oluştur
cat > /etc/pcregrep-patterns/security.txt << 'EOF'
(?i)(?:select|insert|update|delete|drop|union)s+
(?i)(?:script|javascript|vbscript|onload|onerror)s*=
(?i)(?:../){2,}
(?i)(?:cmd.exe|/bin/sh|/bin/bash)s*
(?i)(?:wget|curl)s+http
EOF
# Bu desenleri kullanarak tarama yap
pcregrep -f /etc/pcregrep-patterns/security.txt
/var/log/nginx/access.log
Performans İpuçları
Production ortamında büyük log dosyalarıyla çalışırken performans kritik olabilir.
# Büyük dosyalarda grep ile ön filtreleme yapıp pcregrep'e aktar
# (basit desen için grep daha hızlı çalışır)
grep "ERROR" /var/log/huge-app.log |
pcregrep "(?:NullPointer|OutOfMemory|StackOverflow)Exception.*batb"
# Paralel işlem için GNU parallel ile kullan
ls /var/log/nginx/access.log.* |
parallel "pcregrep -c 'pattern' {} | awk -v f={} '{print f": "$1}'"
# Sadece gerekli alanları çıkar, tüm satırı taşıma
pcregrep -o "(?<=[)[^]]+(?=].*ERROR)" /var/log/app.log
pcregrep ile sed ve awk Kombinasyonu
pcregrep çıktısını diğer araçlarla birleştirince gerçek güç ortaya çıkıyor:
# Log'lardan hata kodlarını çıkar, frekans analizi yap
pcregrep -o "(?<=" )[45]d{2}(?= )" /var/log/nginx/access.log |
sort | uniq -c | sort -rn
# Çok satırlı blokları ayıkla, sadece belirli alanları raporla
pcregrep -M "TRANSACTION START.*nID: d+" transaction.log |
grep -oP "ID: Kd+"
# Config dosyasındaki enabled servisleri listele
pcregrep -M "^[service]n.*enableds*=s*true" services.conf |
grep -oP "(?<=[service-)w+"
Cron Job ve Monitoring Entegrasyonu
Günlük operasyonlarda pcregrepi cron job’larla entegre etmek çok işe yarıyor:
# /etc/cron.d/log-monitor
*/15 * * * * root
pcregrep -c
"(?i)(out of memory|killed process|oom killer)"
/var/log/syslog |
xargs -I{} test {} -gt 0 &&
echo "OOM event tespit edildi" |
logger -t log-monitor -p user.crit
Daha kapsamlı bir monitoring scripti:
#!/bin/bash
# Servis sağlık kontrolü - pcregrep tabanlı
check_service_health() {
local service_name="$1"
local log_file="$2"
local error_threshold="$3"
# Son 100 satırda hata sayısını kontrol et
local error_count
error_count=$(tail -100 "$log_file" |
pcregrep -c "(?i)(error|exception|fatal|critical)")
if [ "$error_count" -gt "$error_threshold" ]; then
echo "UYARI: $service_name - Son 100 log satırında $error_count hata"
# Son hatayı detaylı göster
tail -100 "$log_file" |
pcregrep -M "(?i)(error|exception).*n(?:s+at .*n)*" |
tail -10
return 1
fi
echo "OK: $service_name - $error_count hata (eşik: $error_threshold)"
return 0
}
check_service_health "Tomcat" "/var/log/tomcat9/catalina.out" 5
check_service_health "PostgreSQL" "/var/log/postgresql/postgresql.log" 3
check_service_health "Nginx" "/var/log/nginx/error.log" 10
Sonuç
pcregrep her sysadmin’in araç kutusunda bulunması gereken bir araç. Standart grepten geçiş eğrisi oldukça düşük, ama kazanımlar çok büyük. Özellikle şu üç durumda pcregrepe geçmenizi kesinlikle öneririm:
- Çok satırlı log bloklarını (stack trace, transaction kaydı, XML/JSON parçaları) analiz etmeniz gerektiğinde
- Lookahead/lookbehind gibi gelişmiş regex özelliklerine ihtiyaç duyduğunuzda
- Birden fazla karmaşık deseni tek seferde dosyadan okutarak tarama yapmanız gerektiğinde
Temel grep komutlarını biliyorsanız, pcregrepe adapte olmak için harcayacağınız bir iki saatlik pratik, ilerleyen haftalarda size onlarca saat kazandıracak. Production sorunlarını ayıklarken, güvenlik taramaları yaparken, ya da sadece bir config dosyasında karmaşık bir deseni ararken bu araç defalarca işinize yarayacak.
Son bir not: PCRE regex desenlerini test etmek için regex101.com sitesinde PCRE modunu seçerek desenlerinizi canlı olarak deneyebilirsiniz. Production’da çalıştırmadan önce bu adımı atlamayın.
