0Pricing
Linux Command Line & Bash Scripting Mastery · Ders

Betikleri Profilleme ve Gereksiz Alt Kabuklardan Kaçınma

Betiklerin çalışma süresini ölçün ve cat-grep zincirleri gibi çok sayıda çatallanma oluşturan kalıpları yerleşik alternatiflerle değiştirin.

Betikleri Profilleme ve Gereksiz Alt Kabuklardan Kaçınma, CoddyKit'te ücretsiz bir Linux Command Line & Bash Scripting Mastery dersidir. Bu, 4 dersinin 1. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, Linux Command Line & Bash Scripting Mastery öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Linux Command Line & Bash Scripting Mastery kursu toplamda 4 dersten oluşur.

Betiğin Performansı Neden Önemlidir

Yavaş çalışan Bash betikleri CI süresini boşa harcar, cron işlerini engeller ve kullanıcıları zor durumda bırakır. Yavaşlığın çoğu karmaşık mantıktan kaynaklanmaz; bunun yerine gereksiz işlem çatallarından kaynaklanır: çağırdığınız her harici komut yeni bir alt işlem başlatır.

Bu derste şunları öğreneceksiniz:

  • time ve bash -x ile zamanın gerçekte nereye harcandığını ölçmeyi
  • cat'in gereksiz kullanımı gibi çok sayıda çatal oluşturan karşıt kalıpları belirlemeyi
  • Harici komutları daha hızlı kabuk yerleşikleriyle değiştirmeyi
  • Alt kabukları bilinçli kullanmayı ve değer katmadıklarında bunlardan kaçınmayı

Amaç, aynı işi daha az alt işlemle ve daha kısa gerçek süreyle yapan betikler yazmaktır.

time Yerleşiğiyle Bir Betiğin Süresini Ölçme

En basit profilleme aracı, kabuğun yerleşik time komutudur. Üç ölçüm almak için herhangi bir komutun veya işlem hattının başına ekleyin:

  • real — gerçek geçen süre (gerçekte beklediğiniz süre)
  • user — kullanıcı alanı kodunda harcanan CPU süresi
  • sys — çekirdekte harcanan CPU süresi (sistem çağrıları, G/Ç)

real ile user+sys arasında büyük bir fark olması genellikle betiğin G/Ç beklediği veya çok sayıda alt işlem başlattığı anlamına gelir. Herhangi bir şeyi iyileştirmeden önce bir sorun olduğunu doğrulamak için ilk olarak tüm betiğin etrafında time çalıştırın.

#!/usr/bin/env bash
# Time a whole script block
time {
  for i in $(seq 1 1000); do
    echo "line $i"
  done | grep -c "5"
}
# Output example:
# 271
# real  0m0.045s
# user  0m0.038s
# sys   0m0.012s

bash -x ve PS4 ile Çalıştırmayı İzleme

bash -x, çalıştırmadan önce her komutu yazdırır; buna çalıştırma izleme denir. Hangi satırların en sık çalıştığını ve harici programların beklediğinizden daha fazla çağrılıp çağrılmadığını gösterir.

Varsayılan olarak izlenen her satırın önüne + eklenir. Zaman damgalarını içerecek şekilde PS4 kullanarak bu öneki zenginleştirebilirsiniz; böylece izleme, hafif bir profilleyiciye dönüşür:

  • PS4, izlenen her komuttan önce genişletilir
  • $EPOCHREALTIME (bash 5+) veya $(date +%s%N) eklemek nanosaniye çözünürlüğü sağlar
  • Standart hatayı bir dosyaya yönlendirip yavaş bölümleri bulmak için sonradan işleyin
#!/usr/bin/env bash
# Run with:  bash -x ./myscript.sh  2>trace.log
# Or embed tracing inside the script:
export PS4='+ [${EPOCHREALTIME}] ${BASH_SOURCE}:${LINENO}: '
set -x

slow_function() {
  local result
  result=$(cat /etc/hostname)   # fork — slow
  echo "host: $result"
}

slow_function
set +x

# trace.log now contains timestamps so you can diff
# adjacent lines to find which step took longest.

Gereksiz Alt Kabuk Nedir

Alt kabuk, geçerli kabuk işleminin alt işlem kopyasıdır. Şu yollarla oluşturulur:

  • Komut ikamesi: $(command)
  • Parantezlerle gruplama: ( commands )
  • Bir kabuk yapısına yöneltme: cmd | while read ...

Gerçekten yalıtım veya bir işlem hattı gerektiğinde alt kabuklar gereklidir. Bunları yalnızca kabuğun kendisinin işleyebileceği bir harici programı çağırmak için kullandığınızda veya bir yerleşiği gereksiz yere ek bir çatallama katmanına sardığınızda gereksiz hâle gelirler.

Modern bir Linux sisteminde her alt kabuk çatallaması yaklaşık 1–5 ms sürer. 10.000 kez çalışan bir döngüde 1000 gereksiz alt kabuk, yalnızca ek yük olarak 1–5 saniye ekler.

Klasik Karşıt Kalıp: cat'in Gereksiz Kullanımı

cat file | grep pattern, çok sayıda çatal oluşturan en ünlü karşıt kalıptır. grep dosyayı doğrudan okuyabildiği hâlde, bir işlem hattıyla birbirine bağlanmış iki işlem (cat + grep) başlatır.

Çözüm basittir: dosya adını dosyaları anlayan komuta doğrudan aktarın. Araç dosya adlarını kabul etmiyorsa buna girdi yönlendirme denir; kabul ediyorsa yalnızca cat komutunu kullanmamak yeterlidir.

  • Yavaş: cat file | grep pattern — 2 işlem, 1 işlem hattı
  • Hızlı: grep pattern file — 1 işlem, işlem hattı yok
  • Bu da hızlıdır: grep pattern < file — 1 işlem, standart girdi yönlendirmesi (işlem hattı arabelleği yok)
#!/usr/bin/env bash
# Create a sample file
seq 1 10000 > /tmp/numbers.txt

# --- Slow: useless cat ---
time cat /tmp/numbers.txt | grep -c "^5"

# --- Fast: grep reads the file directly ---
time grep -c "^5" /tmp/numbers.txt

# Both print the same count; the second is measurably faster
# because it skips the cat process and the inter-process pipe.

Harici Komutları Kabuk Yerleşikleriyle Değiştirme

Tek satırlık birçok dönüşümün, çatallamayı tamamen önleyen bir yerleşik karşılığı vardır. Şu yaygın değişiklikleri karşılaştırın:

  • Karakter dizisi uzunluğu için echo ${#var}; echo "$var" | wc -c yerine
  • Büyük/küçük harf dönüşümü için ${var^^} ve ${var,,}; echo "$var" | tr 'a-z' 'A-Z' yerine (bash 4+)
  • Basit değiştirme için ${var//search/replace}; echo "$var" | sed 's/search/replace/' yerine
  • Düzenli ifade eşleşmesi için [[ "$var" =~ pattern ]]; echo "$var" | grep -q pattern yerine
  • İlk satırı okumak için read -r line < file; line=$(head -n1 file) yerine

Bu yerleşiklerin hiçbiri alt işlem çatallamaz. Çağrı başına tasarruf küçük olsa da döngülerin içinde büyük ölçüde birikir.

#!/usr/bin/env bash
sentence="hello world from bash"

# --- Fork-heavy ---
upper_slow=$(echo "$sentence" | tr 'a-z' 'A-Z')
length_slow=$(echo "$sentence" | wc -c)

# --- Builtin equivalents (zero extra processes) ---
upper_fast=${sentence^^}
length_fast=${#sentence}

echo "Slow upper : $upper_slow"
echo "Fast upper : $upper_fast"
echo "Slow length: $length_slow"
echo "Fast length: $length_fast"

Döngülerin İçinde Alt Kabuklardan Kaçınma

Bir döngünün içindeki komut ikamesi, çatallama maliyetini yineleme sayısıyla çarpar. $(date) çağrısı içeren ve 500 kez çalışan bir döngü, yalnızca zaman damgaları için 500 alt işlem başlatır.

Döngü ek yükünü azaltma stratejileri:

  • Değişmeyen komutları döngünün dışına taşıyın (bir kez hesaplayıp yeniden kullanın)
  • Aritmetik genişletmeyi $(( expr )) tercih edin; bu bir yerleşiktir, çatallama değildir
  • Yalnızca biçimlendirme gerektiğinde date çağırmak yerine printf kullanın
  • Harici çağrıları toplu hâle getirin: verileri önce toplayın, döngünün dışında bir kez işleyin
#!/usr/bin/env bash
# Demonstrate: compute-once vs fork-per-iteration

# Bad: $(date) forks 1000 times
time (
  for i in $(seq 1 1000); do
    ts=$(date +%s)   # fork each iteration
    echo "$i $ts" > /dev/null
  done
)

# Good: capture once, reuse
time (
  ts=$(date +%s)   # fork exactly once
  for i in $(seq 1 1000); do
    echo "$i $ts" > /dev/null
  done
)

İşlem Hattı Alt Kabukları ve Değişken Kapsamı Sorunu

bash'te (ksh/zsh'den farklı olarak), bir işlem hattındaki her komut kendi alt kabuğunda çalışır. Bu nedenle bir işlem hattının içinde ayarlanan değişkenler, işlem hattı tamamlandıktan sonra kaybolur.

Bu hem bir doğruluk hatası hem de bir performans sorunudur; veri toplamak amacıyla while read yapısına yönlendirme yapabilir, ancak sonrasında değişkenin boş olduğunu görebilirsiniz.

İki çözüm vardır:

  • İşlem ikamesi kullanın: while read line; do ...; done < <(command) — while döngüsü bir alt kabukta değil, geçerli kabukta çalışır
  • lastpipe seçeneğini kullanın (shopt -s lastpipe) — işlem hattının son bölümünü geçerli kabukta çalıştırır (bash 4.2+)
#!/usr/bin/env bash
count=0

# --- Bug: count is always 0 after pipe (subshell) ---
seq 1 5 | while read -r n; do
  (( count++ ))
done
echo "After pipe   : count=$count"   # prints 0

# --- Fix 1: process substitution (no subshell for while) ---
count=0
while read -r n; do
  (( count++ ))
done < <(seq 1 5)
echo "Process sub  : count=$count"   # prints 5

# --- Fix 2: lastpipe option ---
shopt -s lastpipe
count=0
seq 1 5 | while read -r n; do
  (( count++ ))
done
echo "lastpipe     : count=$count"   # prints 5

Bir Mikro Karşılaştırmayla Alt Kabuk Maliyetini Ölçme

$(( )) (yerleşik) ile gerçekleştirilen bir aritmetik işlemi, aynı işlemin expr (harici işlem) üzerinden yönlendirilmiş hâliyle karşılaştırarak alt kabuk ek yükünü küçük bir karşılaştırmayla kolayca kanıtlayabilirsiniz.

Tipik bir Linux bilgisayarındaki sonuçlar, expr komutuna yapılan 10.000 çağrının yaklaşık 5 saniye sürdüğünü; aynı sayıda $(( )) çağrısının ise 0,1 saniyeden kısa sürdüğünü gösterir. Bu, aynı çıktı için 50 kat fark demektir.

Bu karşılaştırma kalıbı, herhangi bir iyileştirmeyi ölçmek istediğinizde de kullanışlıdır: her iki sürümü bir döngüde N kez çalıştırın ve time ile karşılaştırın.

#!/usr/bin/env bash
N=500

# External command (fork per call)
time (
  x=0
  for ((i=0; i<N; i++)); do
    x=$(expr $x + 1)   # forks expr each time
  done
  echo "expr result: $x"
)

# Arithmetic builtin (no fork)
time (
  x=0
  for ((i=0; i<N; i++)); do
    (( x++ ))          # pure builtin
  done
  echo "builtin result: $x"
)

echo İşlem Hatlarından Kaçınmak için Here-String Kullanma

Bir değişkeni standart girdi olarak beslemek için yaygın olarak echo "$var" | command kalıbı kullanılır. Bu, iki işlem (echo + command) çatallar ve bir işlem hattı oluşturur. Here-string (<<<) aynı sonucu yalnızca bir işlemle elde eder; harici komut, çekirdek tarafından yönetilen geçici bir arabellekten okur.

  • grep pattern <<< "$var" — bir işlem, işlem hattı yok
  • read -r field1 field2 <<< "$line" — harici araç olmadan bir değişkeni bölme
  • wc -w <<< "$sentence" — bir değişkendeki sözcük sayısı

Here-string'ler, her çatallamanın önemli olduğu sıkı döngülerin içinde özellikle değerlidir.

#!/usr/bin/env bash
data="The quick brown fox"

# --- Fork-heavy: echo spawns a child ---
word_count_slow=$(echo "$data" | wc -w)
echo "Slow word count: $word_count_slow"

# --- Fast: here-string, only wc spawns ---
word_count_fast=$(wc -w <<< "$data")
echo "Fast word count: $word_count_fast"

# --- Even better: use parameter expansion (zero forks) ---
# Split into array, count elements
read -ra words <<< "$data"
echo "Zero-fork count: ${#words[@]}"

Uygulamalı Yeniden Düzenleme: Öncesi ve Sonrası

Gerçekçi bir betiğin günlük dosyasını işleyişini inceleyelim ve öğrendiğimiz her şeyi uygulayalım. Özgün sürümde cat, grep, awk ve tr komutları işlem hatlarıyla zincirlenmiştir. Yeniden düzenlenen sürüm, işlem sayısını 8'den 2'ye düşürür.

Yapılan temel değişiklikler:

  • cat kaldırıldı; grep dosyayı doğrudan okuyor
  • tr '[:lower:]' '[:upper:]', ${var^^} ile değiştirildi
  • echo "$line" | grep -q, [[ $line =~ ]] ile değiştirildi
  • İşlem hatlı while döngüsü yerine işlem ikamesiyle birlikte read -r kullanıldı

Yeniden düzenlemeden sonra iyileştirmeyi doğrulamak için time ./script.sh komutunu yeniden çalıştırın. Her zaman ölçün; varsayımda bulunmayın.

#!/usr/bin/env bash
# Create a sample log
printf 'ERROR: disk full\nINFO: started\nERROR: timeout\nINFO: done\n' \
  > /tmp/sample.log

# === BEFORE (fork-heavy) ===
time (
  cat /tmp/sample.log \
    | grep 'ERROR' \
    | while read -r line; do
        label=$(echo "$line" | tr '[:lower:]' '[:upper:]')
        echo "[ALERT] $label"
      done
)

# === AFTER (builtin-first) ===
time (
  while IFS= read -r line; do
    echo "[ALERT] ${line^^}"
  done < <(grep 'ERROR' /tmp/sample.log)
)

Bilgi Kontrolü: Alt Kabuk Kapsamı

Pipeline alt kabukları hakkındaki anlayışınızı ve bir pipe içinde yapılan değişken değişikliklerinin kaybolmasını nasıl önleyeceğinizi sınayın.

Ders Özeti: Önce Profil Oluşturun, Daha Az Çatallayın

Bu derste bash betiklerindeki gereksiz süreç oluşturmanın en yaygın kaynaklarını nasıl belirleyip ortadan kaldıracağınızı öğrendiniz.

Temel çıkarımlar:

  • En iyileştirme yapmadan önce ölçüm almak için time ve PS4 ile zenginleştirilmiş bash -x kullanın
  • Gereksiz cat kullanımı en yaygın anti-pattern'dir — dosya adlarını, bunları kabul eden komutlara doğrudan aktarın
  • echo "$var" | command yerine here-string (command <<< "$var") veya yerleşik bir komut kullanın
  • Parametre genişletmeleri (${var^^}, ${var//s/r}, ${#var}), birçok tr, sed ve wc çağrısının yerini alır
  • Pipeline alt kabukları değişken değişikliklerini yutar — süreç ikamesi veya shopt -s lastpipe kullanın
  • Değişmeyen komut çağrılarını döngülerin dışına taşıyın; expr yerine $(( )) aritmetiğini tercih edin

Pratik kural şudur: önce ölçün, mümkün olduğunda harici komutları yerleşik komutlarla değiştirin ve iyileşmeyi ikinci bir ölçümle doğrulayın.

Sıkça Sorulan Sorular

“Betikleri Profilleme ve Gereksiz Alt Kabuklardan Kaçınma” dersi ücretsiz mi?

Evet — “Betikleri Profilleme ve Gereksiz Alt Kabuklardan Kaçınma” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve Linux Command Line & Bash Scripting Mastery kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Linux Command Line & Bash Scripting Mastery kursu toplamda 4 dersten oluşur.

“Betikleri Profilleme ve Gereksiz Alt Kabuklardan Kaçınma” dersinde ne öğreneceğim?

Betiklerin çalışma süresini ölçün ve cat-grep zincirleri gibi çok sayıda çatallanma oluşturan kalıpları yerleşik alternatiflerle değiştirin. Linux Command Line & Bash Scripting Mastery ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.

Linux Command Line & Bash Scripting Mastery öğrenmeye başlamak için deneyim gerekli mi?

Önceden deneyim gerekmez. CoddyKit'te Linux Command Line & Bash Scripting Mastery, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 1. dersidir.

“Betikleri Profilleme ve Gereksiz Alt Kabuklardan Kaçınma” dersi ne kadar sürer?

Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.

Bu Linux Command Line & Bash Scripting Mastery dersinde kod yazıp çalıştırabilir miyim?

Evet. Her Linux Command Line & Bash Scripting Mastery dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.

Bu kursun tüm dersleri

  1. Betikleri Profilleme ve Gereksiz Alt Kabuklardan Kaçınma
  2. xargs -P ve Arka Plan İşleriyle Paralellik
  3. GNU parallel ile İş Yüklerini Orkestre Etme
  4. Veri Akışları ve İş Hacmi için Adlandırılmış Borular
← Linux Command Line & Bash Scripting Mastery Sayfasına Dön