Shell Scripting ile Fonksiyon Karmaşıklıklarının Daha Derinlerine inmek – Bölüm VII


“Kabuk Betiklerinde Fonksiyonları Anlamak ve Yazmak” hakkındaki önceki makalem size kabuk betikleri altında fonksiyonların nasıl yazılacağı konusunda temel bir fikir vermiş olabilir. Artık yerel değişkenlerin kullanımı ve özyineleme gibi işlevsel özelliklerin derinliklerine inmenin zamanı geldi.

Yerel Değişkenler

Bir değişkeni yerel yapan nedir? Değişkenin bildirildiği belirli bloğa bağlıdır. local olarak bildirilen bir değişkene, göründüğü kod bloğundan erişilebilir, yani kapsamı yereldir. Bu şeyi açıklamak için aşağıdaki bir örneğe bakalım.

#!/bin/bash 

func( ) { 
	local i=10 
	j=20 
	echo "i from func = $i" 
	echo "j from func = $j" 
} 

echo "i outside func = $i" 
echo "j outside func = $j" 

func 

echo "i outside func = $i" 
echo "j outside func = $j" 

exit 0

Yukarıdaki betiği çalıştırdığınızda çıktı olacaktır.

i outside func = 
j outside func = 
i from func = 10 
j from func = 20 
i outside func = 
j outside func = 20

Bunun nedeni, ilk 2 echo ifadesi yürütülürken func fonksiyonunun henüz çağrılmamış olmasıdır. func işlevini çağırdıktan sonra aynı 2 echo ifadesi farklı bir sonuç üretir. Artık func içinde bildirilen ve yerel olmayan j değişkenine daha sonra erişilebiliyordu.

Böylece j'nin değeri 20 olur. Yerel değişken i ne olacak? Kapsamı func fonksiyonunun içinde olduğundan, 10 değerine dışarıdan erişilemedi. Normalde func içinde bildirilen j değişkeninin varsayılan olarak global olduğunu unutmayın.

Artık yerel değişkenlere ve bunların fonksiyon bloklarında nasıl kullanılacağına aşinasınız. Fonksiyonlar başlığı altında en ilginç kısım olan özyinelemeye geçelim.

Özyineleme Nedir?

Kendini çağıran bir fonksiyona genellikle özyineleme prosedürü denir. Veya bir algoritmanın daha basit bir versiyonunu kullanarak ifade edilmesi olarak da tanımlanabilir. Bir sayının faktöriyelini bulma örneğini düşünün. Bunu biliyoruz n!=1 x 2 x 3 x … x (n-1) x n. Böylece bir yineleme ilişkisini şu şekilde yazabiliriz:

n! = (n-1)! x n

Bu nedenle, aynı işlevi yinelemeli olarak çağırmak ve her çağrının dönüş değerini önceki sonuçla çarpmak için kullanmak bizim için kolaydır;

5! = 4! x 5
4! = 3! x 4
3! = 2! x 3
2! = 1! x 2
1! = 0! x 1

Yerel Değişkenleri Kullanarak Özyineleme

Burada yerel değişkenleri ve özyinelemeyi kullanarak bir sayının faktöriyelini bulmak için bir komut dosyası yazmaya çalışıyoruz.

#!/bin/bash 

fact( ) { 
	local num=$1 
	if [ $num -eq 0 ]; then 
		ret=1 
	else 
		temp=$((num-1)) 
		fact $temp 
		ret=$((num*$?)) 
	fi 
	return $ret 
} 

fact 5 

echo "Factorial of 5 = $?" 

exit 0

num, her çağrıda her n-1 değerini depolamak için kullanılan yerel bir değişkendir. Burada temel koşul sayının sıfıra eşit olup olmadığını kontrol eder (0!=1 olduğundan ve negatif sayılar için faktöriyel tanımlanmadığından). Bu temel koşula ulaştığında çağırıcısına 1 değerini döndürür. Şimdi num=1 ve ret=1 x 1.

Şu anda arayan kişiye 1 değerini döndürür. Şimdi num=2 ve ret=2 x 1 vb. Son olarak num=5 olduğunda dönüş değeri 24 olacaktır ve nihai sonuç ret=5 x 24 olacaktır. Nihai sonuç 120 ilk arayan ifadesine aktarılır ve görüntülenir.

Yukarıdaki komut dosyasında bir sorun var. Önceki yazımda da anlattığım gibi fonksiyonlar büyük tamsayılar döndüremezler. Bu nedenle yukarıdaki soruna çözüm bulmak kullanıcılara kalmıştır.

S. Yerel değişkenleri kullanmadan özyineleme gerçekleştirebilir miyiz? Yanıt Evet'tir.

Yerel Değişkenler Olmadan Özyineleme

Özyinelemeyi kullanarak Fibonacci serisini görüntülemek için aşağıdaki örneğe bakın. Temel yineleme ilişkisi:

fib(0) = 0 
fib(1) = 1 
else 
	fib(n) = fib(n-1) + fib(n-2)

Fibonacci series using recursion

#!/bin/bash 

fib( ) { 
	a=$1 
	if [ $a -lt 2 ]; then 
		echo $a 
	else 
		((--a)) 
		b=$(fib $a) 

		((--a)) 
		c=$(fib $a) 

		echo $((b+c)) 
	fi 
} 

for i in $(seq 0 15) 
do 
	out=$(fib $i) 
	echo $out 
done 

exit 0

Yukarıdaki komut dosyasında hiçbir yerel değişken kullanılmamıştır. Umarım yürütme sırasında betiğin akışını anlayabilirsiniz.

Burada 15 değeri, Fibonacci serisinde görüntülenecek terim sayısını temsil eder. Yukarıdaki betiğin yürütülmesiyle ilgili özel bir şey fark ettiniz mi? Biraz zaman alıyor, değil mi? Bir komut dosyasındaki özyineleme, C gibi programlama dillerindeki özyinelemeden daha yavaştır.

Bu yazı ile kabuk komut dosyası yazımındaki işlevler kısmını tamamlamayı planlıyorum. Diziler ve çok daha fazlası hakkında gelecek makalelere ulaşmak için Tecmint ile güncel kalın…