nohup ve disown ile Süreçleri Terminal Bağımsız Çalıştırma

Üretim sunucusunda uzun süren bir işlem başlatıyorsunuz, SSH bağlantınız kopuyor ve sabah geldiğinizde her şeyin sıfırlandığını görüyorsunuz. Bu sahneyi bir kez yaşadıysanız, nohup ve disown komutlarının neden hayat kurtardığını anlamak için fazla açıklamaya gerek yok. Yaşamadıysanız, bu yazıyı okumak o acı deneyimi yaşamadan önce sizi kurtarabilir.

Linux’ta bir terminal oturumu kapandığında, o oturuma bağlı tüm süreçler SIGHUP sinyali alır. Bu sinyal, sürecin durması gerektiğini söyler. Tarihsel olarak bu sinyal, telefon hattı koptuğunda (hangup) terminale gönderilirdi. Günümüzde SSH bağlantısı kesildiğinde, terminal emülatörü kapatıldığında veya oturum sonlandığında aynı şey olur. İşte nohup ve disown tam olarak bu noktada devreye girer.

SIGHUP Neden Önemli?

Bir terminal açtığınızda, sistem bir oturum ve bir süreç grubu oluşturur. Bu oturumun “lider” süreci genellikle shell’inizdir (bash, zsh vb.). O terminal kapandığında, kernel shell’e SIGHUP gönderir, shell de bu sinyali kendi alt süreçlerine iletir. Çoğu süreç bu sinyali aldığında varsayılan davranış olarak sonlanır.

Bunu doğrudan gözlemlemek için şu senaryoyu deneyin:

# Bir terminalde uzun süren bir işlem başlatın
sleep 300 &
echo "PID: $!"

# Terminali kapatın ve başka bir terminalden kontrol edin
ps aux | grep sleep

Terminal kapandıktan sonra sleep sürecinin de gittiğini göreceksiniz. İşte çözmek istediğimiz problem tam olarak bu.

nohup: En Klasik Çözüm

nohup (no hangup) komutu, bir süreci SIGHUP sinyalinden bağışık hale getirerek çalıştırır. Kullanımı son derece basittir:

nohup komut [argümanlar] &

Sondaki & işareti süreci arka plana atar. Teknik olarak nohup olmadan da çalışır ama o zaman süreç ön planda çalışır ve terminal kapanana kadar beklersiniz, ki bu pek mantıklı değildir.

Klasik bir örnek:

nohup python3 veri_isleme.py --input buyuk_dosya.csv --output sonuc.csv &

Bu komut çalıştırıldığında şunu görürsünüz:

[1] 23847
nohup: ignoring input and appending output to 'nohup.out'

nohup varsayılan olarak stdout ve stderr çıktısını bulunduğunuz dizindeki nohup.out dosyasına yazar. Eğer o dizine yazma izniniz yoksa, $HOME/nohup.out dosyasına yazar.

Çıktıyı Yönetmek

nohup.out dosyasını her yerde biriktirmek uzun vadede disk sorunlarına yol açabilir. Çıktıyı yönlendirmek çok daha temiz bir yaklaşım:

# Çıktıyı özel bir log dosyasına yönlendir
nohup python3 analiz.py > /var/log/analiz/cikti.log 2>&1 &

# Hem stdout hem stderr'i ayrı dosyalara yaz
nohup bash yedek_al.sh > /var/log/yedek_stdout.log 2>/var/log/yedek_stderr.log &

# Çıktıyı tamamen yok say (önerilmez ama bazen gerekli)
nohup ./optimize_et.sh > /dev/null 2>&1 &

2>&1 ifadesi stderr’i stdout’a yönlendirir, böylece tek bir dosyada her şeyi yakalarsınız. Bu konfigürasyonu sorun giderme sırasında çok kullanacaksınız.

PID’i Kaydetmek

Süreçleri daha sonra yönetebilmek için PID’lerini kaydetmek iyi bir alışkanlıktır:

nohup ./uzun_islem.sh > islem.log 2>&1 &
echo $! > /var/run/uzun_islem.pid
echo "Süreç başlatıldı, PID: $(cat /var/run/uzun_islem.pid)"

Daha sonra bu süreci durdurmak için:

kill $(cat /var/run/uzun_islem.pid)

disown: Zaten Başlamış Süreçler İçin

nohup‘ın bir sorunu var: süreci başlatmadan önce kullanmanız gerekiyor. Peki ya 45 dakika önce başlattığınız ve hâlâ devam eden o büyük rsync işlemini ne yapacaksınız? SSH bağlantınız kopacak gibi görünüyor ve işlemi baştan başlatmak felakete yol açacak.

İşte disown tam bu senaryolar için var. Bash’in built-in komutu olan disown, halihazırda çalışan bir süreci shell’in iş (job) listesinden çıkarır. Bu sayede süreç, shell kapanırken SIGHUP almaz.

Önce temel kullanımı görelim. Diyelim ki bir işlemi yanlışlıkla nohup olmadan başlattınız:

# Ön planda çalışan bir işlemi Ctrl+Z ile durdur
rsync -avz /data/ yedek_sunucu:/backup/data/
# Ctrl+Z basın
[1]+  Stopped                 rsync -avz /data/ yedek_sunucu:/backup/data/

# Arka plana gönder
bg %1

# Job listesini kontrol et
jobs
[1]+  Running                 rsync -avz /data/ yedek_sunucu:/backup/data/ &

# Shell'den kopar
disown %1

# Artık jobs listesinde görünmez
jobs
# (boş çıktı)

disown Parametreleri

-h: Süreci job listesinden çıkarmaz ama SIGHUP almayacak şekilde işaretler. Süreci jobs listesinde görmek istiyorsanız bu seçeneği kullanın.

-a: Tüm jobları disown eder.

-r: Sadece çalışan (running) jobları disown eder.

Pratikte en çok kullanılan formlar:

# Son arka plan sürecini disown et
disown

# Belirli bir job numarasını disown et
disown %2

# PID ile disown et
disown 23847

# Tüm arka plan süreçlerini disown et
disown -a

# SIGHUP'tan koru ama listede tut
disown -h %1

Gerçek Senaryo: Kaçan SSH Oturumu

Sabah mesaiye geldiniz, büyük bir veritabanı yedekleme işlemi başlatmanız gerekiyor. VPN bağlantısı kararsız, çalışacak ve başka işleriniz var. Klasik senaryo:

# İşlemi başlat
pg_dump -Fc -d uretim_db -U postgres > /backup/uretim_$(date +%Y%m%d_%H%M%S).dump

# Bekle, bu çok uzun sürecek!
# Ctrl+Z
[1]+  Stopped                 pg_dump -Fc -d uretim_db...

# Arka plana gönder
bg %1

# Shell'den kopar ve güvende ol
disown -h %1

# PID'i not al
jobs -l

nohup ve disown’u Birlikte Anlamak

Bu iki araç farklı sorunları çözer ama sıkça karıştırılır. Özet olarak:

  • nohup: Başlamadan önce kullanılır, SIGHUP’ı engeller ve çıktıyı dosyaya yönlendirir.
  • disown: Başladıktan sonra kullanılır, süreci shell’in kontrolünden çıkarır.

Dikkat edilmesi gereken önemli bir nokta: disown ile bir süreci shell’den kopardığınızda, eğer o sürecin stdin/stdout/stderr terminale bağlıysa ve terminal kapanırsa, I/O hataları alabilirsiniz. Bu yüzden disown kullanmadan önce I/O yönlendirmesi yapmanız önerilir:

# Kötü yol: I/O hâlâ terminale bağlı
./islem.sh &
disown

# İyi yol: Önce I/O'yu yönlendir
./islem.sh > /tmp/islem.log 2>&1 &
disown

screen ve tmux ile Karşılaştırma

Bu noktada “neden screen veya tmux kullanmıyoruz?” diye sorabilirsiniz. Meşru bir soru. screen ve tmux terminal multiplexer olarak çok daha kapsamlı özellikler sunar: oturumu istediğiniz zaman tekrar bağlanabilir, birden fazla pencere açabilirsiniz. Uzun vadeli ve interaktif işler için kesinlikle tercih edilirler.

Ama nohup ve disown‘un hâlâ değeri var:

  • Kurulum gerektirmez: Neredeyse her Linux sistemde varsayılan olarak bulunur.
  • Basit scriptlerde: Bir cron job veya otomasyon scriptinden süreç başlatırken nohup yeterlidir.
  • Anlık müdahaleler: Çalışan bir süreci kurtarmak için disown hızlıdır.
  • Minimal sistemler: Docker container veya kısıtlı ortamlarda screen/tmux olmayabilir.

Gerçek Dünya Senaryoları

Senaryo 1: Büyük Dosya Transferi

Sunucular arası büyük veri taşıması yapıyorsunuz. Bu işlem saatler sürebilir:

nohup rsync -avz --progress 
    --bwlimit=50000 
    /data/arsiv/ 
    yedek01.sirket.local:/data/arsiv/ 
    > /var/log/rsync_transfer_$(date +%Y%m%d).log 2>&1 &

echo "Transfer başladı. PID: $!"
echo $! > /tmp/rsync_transfer.pid

İlerlemeyi takip etmek için:

tail -f /var/log/rsync_transfer_$(date +%Y%m%d).log

Senaryo 2: Yazılım Derleme

Kernel veya büyük bir yazılım derliyorsunuz, bu işlem gerçekten uzun sürer:

cd /usr/src/linux
nohup make -j$(nproc) > /tmp/kernel_build.log 2>&1 &
echo "Derleme başladı. Log için: tail -f /tmp/kernel_build.log"

Derleme bitince bilgi almak ister misiniz? Basit bir wrapper:

nohup bash -c 'make -j$(nproc) && echo "BASARILI" | mail -s "Derleme Bitti" [email protected] || echo "HATA" | mail -s "Derleme Basarisiz" [email protected]' > /tmp/build.log 2>&1 &

Senaryo 3: Periyodik Kontrol İşlemi

Bir servisi izleyen ve sorun olduğunda müdahale eden script:

cat > /tmp/servis_izle.sh << 'EOF'
#!/bin/bash
while true; do
    if ! systemctl is-active --quiet nginx; then
        echo "$(date): Nginx durdu, yeniden başlatılıyor..." >> /var/log/nginx_izle.log
        systemctl start nginx
    fi
    sleep 30
done
EOF

chmod +x /tmp/servis_izle.sh
nohup /tmp/servis_izle.sh > /var/log/nginx_izle.log 2>&1 &
echo $! > /var/run/nginx_izle.pid

Senaryo 4: Zaten Çalışan Süreci Kurtarmak

Bu en kritik senaryo. Bir işlemi başlattınız, SSH kopacak gibi görünüyor:

# Süreç ön planda çalışıyor, PID'i bul
# Önce Ctrl+Z ile durdur

# Job listesine bak
jobs -l
[1]+ 31547 Stopped    python3 ml_model_egitim.py

# Arka plana gönder
bg %1

# Doğrula: çalışıyor mu?
jobs -l
[1]+ 31547 Running    python3 ml_model_egitim.py &

# Shell'den kopar
disown 31547

# Artık terminal kapansa bile süreç devam eder
# Süreci başka bir terminalden takip et
ps -p 31547 -o pid,ppid,stat,cmd

İşlerin Durumunu Takip Etmek

Süreci shell’den kopardıktan sonra nasıl takip edeceksiniz?

# PID ile durum kontrolü
ps -p $(cat /var/run/islem.pid) -o pid,ppid,stat,%cpu,%mem,cmd

# Sürecin ürettiği dosyayı izle
tail -f /var/log/islem.log

# Süreç hâlâ çalışıyor mu?
kill -0 $(cat /var/run/islem.pid) 2>/dev/null && echo "Çalışıyor" || echo "Durdu"

# Sürecin açtığı dosya tanımlayıcılarını listele
lsof -p $(cat /var/run/islem.pid)

# Sürecin sistem çağrılarını izle (debug için)
strace -p $(cat /var/run/islem.pid) -e trace=network 2>&1 | head -50

Birden fazla süreci yönetiyorsanız basit bir kontrol scripti işinizi kolaylaştırır:

#!/bin/bash
# surecler.sh - Yönetilen süreçleri kontrol et

PID_DIR="/var/run/yonetilen"

for pid_dosya in $PID_DIR/*.pid; do
    isim=$(basename $pid_dosya .pid)
    pid=$(cat $pid_dosya)
    
    if kill -0 $pid 2>/dev/null; then
        durum="CALISIYOR"
        cpu=$(ps -p $pid -o %cpu= | tr -d ' ')
        echo "[$isim] PID:$pid DURUM:$durum CPU:%$cpu"
    else
        echo "[$isim] PID:$pid DURUM:DURDU"
    fi
done

Dikkat Edilmesi Gereken Noktalar

Zombie süreçler: disown kullandığınızda, süreç tamamlandığında shell o exit status’ı toplayamaz. Bu teknik olarak zombie sürece yol açabilir ama genellikle init/systemd sahipliği devralır ve temizler. Kritik üretim ortamlarında systemd unit dosyaları daha güvenlidir.

Arka plan süreci ve terminal I/O: Disown edilmiş bir süreç terminale yazmaya çalışırsa SIGTTOU veya SIGTTIN alabilir. Bunu önlemek için tüm I/O’yu dosyalara yönlendirin.

nohup.out birikimi: Varsayılan nohup.out dosyasını kontrol altında tutun. Otomatik log döndürme için logrotate kullanmayı düşünün.

Güvenlik: Arka planda çalışan süreçler gözden kaçabilir. Kritik sistemlerde hangi süreçlerin arka planda çalıştığını düzenli kontrol edin:

# Kontrolsüz arka plan süreçlerini bul
ps -eo pid,ppid,user,stat,cmd | grep -v '[' | awk '$2 == 1 && $4 != "Z"'

Sonuç

nohup ve disown küçük ama kritik araçlardır. Her sistem yöneticisinin kas belleğine işlenmiş olması gereken komutlardır bunlar. nohup, işi başlatmadan önce garanti altına alır; disown ise o “ah umarım bağlantım kesilmez” anında bir can simidi olur.

Gerçek hayatta en sağlıklı yaklaşım şu hiyerarşidir: kısa ve basit arka plan işler için nohup, acil durum kurtarma için disown, uzun süreli interaktif oturumlar için tmux veya screen, ve üretim servisleri için systemd unit dosyaları. Her aracın yeri ve zamanı var; hangisini ne zaman kullanacağınızı bilmek, iyi bir sistem yöneticisinin temel ayırt edici özelliklerinden biridir.

Bir dahaki SSH bağlantınız koptuğunda, o “Ctrl+Z, bg, disown” refleksi sizi kurtaracak.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir