kill ve pkill ile Süreç Sonlandırma

Bir sistem yöneticisinin en sık başvurduğu becerilerden biri, kontrolden çıkmış veya yanıt vermeyi bırakan süreçleri sonlandırmaktır. Sunucunda donup kalan bir uygulama, belleği tüketen bir zombie process veya yanlışlıkla başlatılan bir script… Bunların hepsinin çözümü kill ve pkill komutlarından geçiyor. Bu yazıda bu iki komutu tüm detaylarıyla ele alacağız.

Sinyaller: kill Komutunun Temeli

kill komutunun adı biraz yanıltıcı, çünkü bu komut aslında her zaman bir süreci “öldürmüyor”. Teknik olarak kill, bir sürece sinyal gönderen bir araç. Süreç bu sinyali alıp ne yapacağına kendisi karar veriyor, ya da bazı sinyallerde sistem süreci sonlandırıyor.

Linux’ta onlarca sinyal türü var ama sistem yöneticileri olarak günlük işlerimizde birkaç tanesini kullanıyoruz:

  • SIGTERM (15): Nazik sonlandırma isteği. Sürece “lütfen kapat kendini” diyorsun. Uygulama bu sinyali yakalayıp temiz bir şekilde kapanabilir, dosyalarını yazabilir, bağlantılarını kapatabilir. Varsayılan sinyal bu.
  • SIGKILL (9): Anında ve zorla sonlandırma. Kernel seviyesinde gerçekleşir, uygulama bu sinyali yakalayamaz veya görmezden gelemez. Nükleer seçenek.
  • SIGHUP (1): Tarihsel olarak terminal bağlantısının kopmasını temsil eder. Pek çok daemon bu sinyali alınca konfigürasyon dosyasını yeniden yükler. Nginx, Apache gibi servisler için çok kullanışlı.
  • SIGINT (2): Klavyeden Ctrl+C basıldığında gönderilen sinyal. Programı kesintiye uğrat.
  • SIGSTOP (19): Süreci durdurur (askıya alır), sonlandırmaz. Dondurulmuş süreç gibi düşün.
  • SIGCONT (18): SIGSTOP ile durdurulmuş süreci devam ettirir.

Sisteminizde desteklenen tüm sinyalleri görmek için:

kill -l

kill Komutu: PID ile Süreç Sonlandırma

kill komutunun temel sözdizimi şu şekilde:

kill [sinyal] PID

Sinyal belirtmezsen varsayılan olarak SIGTERM (15) gönderilir. Önce en basit kullanımdan başlayalım. Diyelim ki PID’i 1234 olan bir süreci sonlandırmak istiyorsun:

kill 1234

Bu komut sürece SIGTERM gönderir. Süreç buna cevap vermiyorsa, yani zombi gibi takılı kaldıysa, o zaman SIGKILL sıraya giriyor:

kill -9 1234

Ya da sinyal adını sayı yerine ismiyle de kullanabilirsin:

kill -SIGKILL 1234
kill -KILL 1234

Birden fazla süreci aynı anda sonlandırmak için PID’leri yan yana yazabilirsin:

kill 1234 5678 9012

PID’i Nasıl Bulursun?

kill ile iş yapmadan önce tabii ki sonlandırmak istediğin sürecin PID’ini bilmen gerekiyor. Bunun için birkaç yol var:

# ps ile PID bul
ps aux | grep nginx

# pgrep ile sadece PID'leri listele
pgrep nginx

# pidof komutu da çalışır
pidof nginx

# Daha detaylı bilgi için
ps -ef | grep "python script.py"

Gerçek bir senaryodan bahsedelim. Diyelim ki production sunucunda bir Java uygulaması var ve GC (garbage collection) problemi yaşıyor, yüksek CPU tüketiyor. Önce durumu tespit ediyorsun:

ps aux --sort=-%cpu | head -10

Çıktıda o Java process’in PID’ini gördün, diyelim ki 4521. Önce nazikçe sonlandırmayı dene:

kill -15 4521

Birkaç saniye bekle, hala çalışıyorsa:

kill -9 4521

pkill Komutu: İsimle Süreç Sonlandırma

pkill, kill komutunun daha akıllı kardeşi. PID yerine doğrudan süreç adı veya diğer özelliklerine göre sinyal gönderebiliyorsun. Bu, özellikle PID bulmakla uğraşmak istemediğin durumlarda hayat kurtarıyor.

Temel kullanımı şöyle:

pkill nginx

Bu komut, adında “nginx” geçen tüm süreçlere SIGTERM gönderir. Dikkat et, “adında geçen” dedim, tam eşleşme aranmıyor varsayılan olarak.

pkill Parametreleri

  • -signal: Gönderilecek sinyali belirtir. pkill -9 nginx gibi.
  • -x: Tam isim eşleşmesi arar. “nginx” yazarsan sadece adı tam olarak “nginx” olan süreci bulur, “nginx-worker” gibi şeyleri atlar.
  • -f: Komut satırının tamamına göre arama yapar, sadece süreç adına değil.
  • -u kullanıcı: Belirli bir kullanıcıya ait süreçleri hedef alır.
  • -g grup: Belirli bir process grubunu hedef alır.
  • -t terminal: Belirli bir terminalden başlatılmış süreçleri hedef alır.
  • -n: En yeni (en son başlatılmış) eşleşen süreci hedef alır.
  • -o: En eski (en ilk başlatılmış) eşleşen süreci hedef alır.
  • -l: Eşleşen süreçlerin adlarını PID ile birlikte listeler (sonlandırmadan önce doğrulama için harika).
  • -e: Hangi süreci sonlandırdığını ekrana yazar.
# Tam isim eşleşmesiyle sonlandır
pkill -x nginx

# Tüm Python scriptlerini sonlandır
pkill -f "python"

# Belirli bir scripti çalıştıran süreci bul ve sonlandır
pkill -f "backup_script.py"

# Belirli bir kullanıcının tüm süreçlerini sonlandır
pkill -u ahmet

# Sonlandırmadan önce hangi süreçlerin etkileneceğini gör
pkill -l nginx

Gerçek Dünya Senaryoları

Senaryo 1: Yanıt Vermeyen Web Sunucusu

Nginx worker process’lerinden biri takılı kalmış ve CPU’yu yiyor. Graceful restart yapmak istiyorsun:

# Önce mevcut durumu kontrol et
ps aux | grep nginx

# SIGHUP ile nginx'i konfigürasyonu yeniden yüklemesi için zorla
pkill -HUP nginx

# Eğer sorun devam ederse tüm nginx process'lerini öldür ve yeniden başlat
pkill nginx
systemctl start nginx

Senaryo 2: Runaway Script

Bir bash scripti yanlışlıkla sonsuz döngüye girmiş ve sistem kaynaklarını tüketiyor:

# Çalışan scriptin adını ve PID'ini bul
ps aux | grep infinite_loop.sh

# pkill ile scripti sonlandır
pkill -f "infinite_loop.sh"

# Eğer birden fazla instance varsa ve hepsini kapatmak istiyorsan
pkill -9 -f "infinite_loop.sh"

Senaryo 3: Belirli Kullanıcının Oturumunu Temizleme

Bir kullanıcı sunucuya SSH ile bağlanmış, bazı ağır işlemler başlatmış ve şu an erişilemez durumda. Yönetici olarak o kullanıcının tüm süreçlerini temizlemen gerekiyor:

# Kullanıcının çalışan süreçlerini listele
ps -u testuser

# Tüm süreçlerine SIGTERM gönder
pkill -u testuser

# Inat ediyorlarsa SIGKILL
pkill -9 -u testuser

Senaryo 4: Zombie Process Temizleme

Zombie process’ler genellikle parent process’leri tarafından beklenmeyen çocuk süreçlerdir. Zombie’yi doğrudan kill ile sonlandıramazsın, ama parent’ını bulup ona SIGCHLD gönderebilirsin:

# Zombie process'leri bul (Z durumundakiler)
ps aux | grep 'Z'

# Zombie'nin parent PID'ini bul (PPID kolonuna bak)
ps -o pid,ppid,stat,comm | grep Z

# Parent'a SIGCHLD gönder
kill -SIGCHLD [PPID]

# Eğer çalışmazsa parent'ı yeniden başlat
kill -HUP [PPID]

Senaryo 5: Belirli Bir Port’u Kullanan Süreci Sonlandırma

Bu çok karşılaşılan bir durum, “port zaten kullanımda” hatası alıyorsun ve o portu kullanan süreci kapatman gerekiyor:

# 8080 portunu kullanan süreci bul
lsof -ti:8080

# Doğrudan sonlandır
kill $(lsof -ti:8080)

# Ya da fuser ile
fuser -k 8080/tcp

# Birden fazla port varsa
kill $(lsof -ti:8080 -ti:8081)

kill ile Süreç Grubuna Sinyal Gönderme

Bazen birbirleriyle ilişkili, aynı parent process’ten doğmuş bir grup süreci toplu sonlandırmak istersin. Bunun için negatif PID kullanımı devreye giriyor:

# PGID'i bul
ps -o pgid,pid,cmd | grep myapp

# Tüm gruba sinyal gönder (negatif PGID kullan)
kill -TERM -1234

Burada -1234 yazmak, PGID’i 1234 olan tüm sürçlere sinyal gönder anlamına geliyor.

Sinyal Göndermenin Güvenli Yolu: Önce Kontrol Et

Production ortamında yanlışlıkla kritik bir süreci sonlandırmak gerçekten kötü sonuçlar doğurabilir. Bu yüzden pgrep kullanarak önce hangi süreçleri etkileyeceğini kontrol etmek iyi bir alışkanlık:

# Önce hangi süreçlerin etkileceğini gör
pgrep -la nginx

# Sonuçtan memnunsan sonlandır
pkill nginx

pgrep ile pkill aynı argümanları kullanıyor, dolayısıyla pgrep ile test ettiğin kalıp pkill ile de aynı süreçleri bulacak.

kill -9’u Ne Zaman Kullanmalı, Ne Zaman Kullanmamalı?

Bu sorunun cevabı sistem yöneticiliğinde önemli bir yer tutuyor. SIGKILL’i (kill -9) bir son çare olarak düşünmek gerekiyor.

SIGKILL kullanmanın sakıncaları:

  • Uygulama açık dosyalarını düzgün kapatamaz, veri kaybına yol açabilir.
  • Veritabanları için özellikle tehlikeli: uncommitted transaction’lar kaybolabilir.
  • Shared memory, semaphore gibi IPC kaynakları temizlenmeden kalabilir.
  • Geçici dosyalar, lock dosyaları silinmeden kalır.

Doğru yaklaşım:

# 1. Önce nazikçe sor (SIGTERM)
kill -15 PID
sleep 5

# 2. Hala çalışıyor mu kontrol et
if kill -0 PID 2>/dev/null; then
    echo "Süreç hala çalışıyor, SIGKILL gönderiliyor..."
    kill -9 PID
fi

Bu pattern’i bir script içine alabilirsin:

#!/bin/bash
graceful_kill() {
    local pid=$1
    local timeout=${2:-10}

    echo "PID $pid'e SIGTERM gönderiliyor..."
    kill -15 "$pid" 2>/dev/null

    local count=0
    while kill -0 "$pid" 2>/dev/null; do
        if [ $count -ge $timeout ]; then
            echo "Timeout asildi, SIGKILL gönderiliyor..."
            kill -9 "$pid" 2>/dev/null
            return
        fi
        sleep 1
        ((count++))
    done

    echo "Süreç $pid basariyla sonlandirildi."
}

# Kullanım
graceful_kill 1234
graceful_kill 5678 20  # 20 saniye bekle

pgrep ile kill Kombinasyonu

pgrep ve kill‘i birleştirerek çok güçlü komutlar yazabilirsin:

# pgrep çıktısını kill'e aktar
kill $(pgrep -f "old_app")

# Birden fazla process için
pgrep -f "worker" | xargs kill -9

# Belirli kullanıcıya ait, belirli bir komutla başlayan süreçleri öldür
pgrep -u deploy -f "python app.py" | xargs kill -15

Özel Durumlar ve İpuçları

init veya systemd Süreçlerine Dokunma

PID 1 olan init ya da systemd’ye sinyal göndermek istersen sistem çökmesi yaşanabilir. Kernel bu konuda bazı korumalar sunuyor ama yine de dikkatli olmak gerekiyor:

# PID 1'e kesinlikle kill -9 gönderme!
# SIGHUP gönderebilirsin, systemd bunu yeniden yapılandırma olarak yorumlar
kill -HUP 1

Terminal Kapandığında Süreç Çalışmaya Devam Etsin

Bazen bir süreci başlattıktan sonra terminalin kapanmasıyla birlikte SIGHUP alıp ölmesini istemezsin. Bunun için nohup veya disown kullanılır, ama konu dışına çıkmayalım.

kill ve sudo

Başka kullanıcılara ait süreçlere sinyal gönderebilmek için root yetkisi gerekiyor:

# Root olmadan başkasının sürecini sonlandıramazsın
sudo kill -9 1234
sudo pkill -u www-data nginx

Yanlışlıkla Tüm Süreçleri Sonlandırma Tehlikesi

Çok dikkat edilmesi gereken bir durum var. Şu iki komut arasındaki farka bak:

# DOĞRU: nginx'e sinyal gönder
pkill nginx

# TEHLİKELİ: Boşluk sorunu, tüm süreçlere sinyal gönderebilir
pkill $PROCESS_NAME  # PROCESS_NAME değişkeni boşsa...

Değişken kullanırken her zaman tırnak içine al:

pkill "$PROCESS_NAME"

Monitoring ile Entegrasyon

Gerçek production ortamlarında tek seferlik kill komutlarından çok, bu komutlar monitoring scriptleri içine entegre ediliyor:

#!/bin/bash
# Bellek kullanimini kontrol eden ve limit asan sürecleri sonlandiran script

MEMORY_LIMIT=80  # Yüzde olarak

while true; do
    # Bellek yüzdesine göre sıralanmış süreçleri kontrol et
    ps aux --sort=-%mem | tail -n +2 | while read user pid cpu mem vsz rss tty stat start time cmd; do
        mem_int=${mem%.*}
        if [ "$mem_int" -gt "$MEMORY_LIMIT" ]; then
            echo "$(date): PID $pid ($cmd) %$mem bellek kullaniyor, sonlandiriliyor..."
            kill -15 "$pid"
            sleep 3
            kill -0 "$pid" 2>/dev/null && kill -9 "$pid"
        fi
    done
    sleep 60
done

Sonuç

kill ve pkill komutları, Linux sistem yönetiminin olmazsa olmaz araçları. Yüzeysel bakışta basit görünseler de sinyal mekanizmasını anladığında çok daha etkili kullanabiliyorsun.

Özetleyecek olursak: Önce SIGTERM, son çare SIGKILL. Bu kurala uymak, veri kaybını ve sistem kararsızlığını minimize eder. pkill kullanmadan önce pgrep ile hedef süreçleri doğrula, production ortamında aceleci davranma.

Sinyaller konusuna hakim olduktan sonra systemctl, supervisorctl veya benzeri servis yöneticileriyle çalışırken de bu temel bilginin ne kadar değerli olduğunu göreceksin. Sonuçta bu araçlar da arka planda aynı sinyal mekanizmasını kullanıyor.

Yorum yapın