Shell Script #11 – Döngüler (for, while, until)

Shell döngüleri, bir komut setini belirli bir sayıda ya da belirli bir koşul altında tekrar tekrar çalıştırabilmenizi sağlar. Bu yazıda, 3 çeşit döngü yapısından bahsedeceğiz: for, while ve until.

Shell Script for Döngüsü

for döngüsü; komutlarını, argüman listesindeki her bir eleman için tekrarlar. Yapısı, aşağıdaki gibidir:

for degisken in liste
do
      #komutlar
done

Burada;

  • “liste”, bir string ya da numara listesidir.
  • “degisken”, adından da anlaşılacağı üzere döngü içinde kullanılacak değişkendir. “liste”den gelen elemanlar “degisken”de tutulur.

Örnek kod:

#! /bin/bash


#for döngüsü örnekleri:


#Listedeki tüm elemanları ekrana yazdır:
for oyuncu in Neville Ferdinand Giggs Scholes Rooney "van Nistelrooy"
do
	echo "Sıradaki oyuncu: $oyuncu"
done

Burada liste olarak bir kelime listesi verdik. Döngü ilerledikçe, “oyuncu” değişkeninin değeri, listedeki elemanları tek tek gezecek. “van Nistelrooy“a dikkat edin. İki kelimelik bir değer verdiğim için tırnak işaretleri arasında. Aksi durumda, “van” ve “Nistelrooy” şeklinde 2 ayrı eleman olarak algılanacaktı.

Script’in çıktısı ise şöyle olacak:

[root@gnuadmin ShellScripting101]# ./18-for_dongusu_ornekleri.sh 
Sıradaki oyuncu: Neville
Sıradaki oyuncu: Ferdinand
Sıradaki oyuncu: Giggs
Sıradaki oyuncu: Scholes
Sıradaki oyuncu: Rooney
Sıradaki oyuncu: van Nistelrooy
Shell script for döngüsü
Shell script for döngüsü

Script’te gelen tüm argümanları, for döngüsüyle yazdırabiliriz. Bunun için “$*” meta karakterini kullanabiliriz. “$*”, script’inize gelen tüm argümanların listesidir:

#Script'te gelen tüm argümanları ekrana yazdır:

counter=1
for arg in $*
do
	echo "$counter. argüman: $arg"
	let counter=counter+1
done
[root@gnuadmin ShellScripting101]# ./18-for_dongusu_ornekleri.sh The Lord of the Rings
1. argüman: The
2. argüman: Lord
3. argüman: of
4. argüman: the
5. argüman: Rings

for döngünüze argüman listesi olarak bir komutun çıktısını da verebilirsiniz. Örneğin, “/etc/passwd” dosyasını okuyalım ve kullanıcı adlarını çekelim. Sonrasında da tüm bu kullanıcıları ekrana yazdıralım:

#Sistemdeki tüm kullanıcıları ekrana yazdır:

counter=1
for kullanici in $(cat /etc/passwd | cut -d ":" -f 1)
do
	echo "Dosyadaki $counter. kullanıcı: $kullanici"
	let counter=counter+1
done

Kodun çıktısı ise şu şekilde olacaktır:

[root@gnuadmin ShellScripting101]# ./18-for_dongusu_ornekleri.sh 
Dosyadaki 1. kullanıcı: root
Dosyadaki 2. kullanıcı: bin
Dosyadaki 3. kullanıcı: daemon
Dosyadaki 4. kullanıcı: adm
Dosyadaki 5. kullanıcı: lp
Dosyadaki 6. kullanıcı: sync
Dosyadaki 7. kullanıcı: shutdown
Dosyadaki 8. kullanıcı: halt
Dosyadaki 9. kullanıcı: mail
Dosyadaki 10. kullanıcı: operator
Dosyadaki 11. kullanıcı: games
Dosyadaki 12. kullanıcı: ftp
Dosyadaki 13. kullanıcı: nobody
Dosyadaki 14. kullanıcı: systemd-network
Dosyadaki 15. kullanıcı: dbus
Dosyadaki 16. kullanıcı: polkitd
Dosyadaki 17. kullanıcı: sshd
Dosyadaki 18. kullanıcı: postfix
Dosyadaki 19. kullanıcı: mysql
Dosyadaki 20. kullanıcı: apache

Wildcard kullanımı da pekala mümkün. Aşağıdaki script, “/var/log” dizinindeki “s” harfi ile başlayan dosya ve dizinleri listeler:

#Wildcard kullanım örneği:

for dosya in $(ls /var/log/s*)
do
	echo $dosya
done
[root@gnuadmin ShellScripting101]# ./18-for_dongusu_ornekleri.sh 
/var/log/secure
/var/log/secure-20211226
/var/log/secure-20220110
/var/log/spooler
/var/log/spooler-20211226
/var/log/spooler-20220110

Basitçe, bir komut setini belirli sayıda çalıştırmak için de aşağıdaki syntax’ı kullanabilirsiniz:

#Sayılarla kullanım örneği:
echo "Beni seq kullanarak yazdılar:"
for sayi in $(seq 5)
do
	echo $sayi
done


echo "Beni bir sayı aralığı kullanarak yazdırdılar:"
for sayi in {6..10}
do
	echo $sayi
done


echo "Beni tek satırda yazdılar:"
for sayi in {11..15}; do echo $sayi; done

Çıktısı aşağıdaki gibidir:

Beni seq kullanarak yazdılar:
1
2
3
4
5
Beni bir sayı aralığı kullanarak yazdırdılar:
6
7
8
9
10
Beni tek satırda yazdılar:
11
12
13
14
15

Shell döngüleri, for ile sınırlı değil. Şimdi de “while” döngüsüne bakalım.

Shell Script while Döngüsü

while döngüsü; komutlarını, belirli bir koşul sağlandıkça çalıştırır. Yapısı, aşağıdaki gibidir:

while kontrol_komutu
do
      #komutlar
done

Burada “kontrol_komutu”, “success” ya da “fail” dönüşü yapabilen herhangi bir komut olabilir. “kontrol_komutu” başarıyla çıkış yaptığı sürece, “do” ve “done” arasındaki komutlar çalışır.

Örnek script:

#! /bin/bash

#while döngüsü örnekleri

#sayi değişkeninin değeri 10'dan küçük olduğu sürece döngü çalışır:

sayi=0

while [[ $sayi -lt 10 ]]
do
	echo $sayi
	let sayi=sayi+1
done

Kodun çıktısı ise şu şekilde olacaktır:

[root@gnuadmin ShellScripting101]# ./19-while_dongusu_ornekleri.sh 
0
1
2
3
4
5
6
7
8
9

Kullanıcıdan alınan sayıların toplamını veren bir while döngüsü yazalım:

#Kullanıcıdan alınan sayıların toplamı:

toplam=0
echo "Çıkmak için Ctrl+D kombinasyonunu kullanın"
printf "Bir sayı girin: "

while read sayi
do
	let toplam=toplam+sayi
	printf "Bir sayı girin: "
done
echo ""
echo "Girdiğiniz sayıların toplamı: $toplam"

Çıktı:

Çıkmak için Ctrl+D kombinasyonunu kullanın
Bir sayı girin: 10
Bir sayı girin: 20
Bir sayı girin: 30
Bir sayı girin: 40
Bir sayı girin: 50
Bir sayı girin: 
Girdiğiniz sayıların toplamı: 150

while döngüsüne input yönlendirme

Bazı durumlarda, döngünüzün kontrolünü bir input listesine göre yapmak isteyebilirsiniz. for döngüsünde yaptığımız “kullanıcıları yazdırma” örneğini bir de while döngüsü ile yapmayı deneyelim.

IFS=:” satırıyla, dosyada kullanılan ayraçın (seperator) iki nokta üst üste olduğunu belirtiyoruz. Bu arkadaşa “Internal Field Seperator” denir. Döngüyü, “/root/users.txt” dosyasıyla besliyoruz:

Dosya içeriği:

[root@gnuadmin ShellScripting101]# cat /root/users.txt 
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
halt:7
mail:8
operator:11
games:12
ftp:14
nobody:99
systemd-network:192
dbus:81
polkitd:999
sshd:74
postfix:89
mysql:998
apache:48

Script:

#while döngüsüne input yönlendirme

#/etc/passwd dosyasından kullanıcı adı ve ID'lerini al:
#Internal Field Seperator
IFS=:

while read user id
do
	echo "$id ID'li kullanıcı: $user"
done < /root/users.txt

Çıktımız ise aşağıdaki gibi olacaktır:

Shell script while örneği
Shell script while örneği

Bir başka shell döngüsü olan “until” ile devam edelim.

Shell Script until Döngüsü

while döngüsüne çok benzer. Ancak while döngüsünde, “kontrol_komutu” başarılı oldukça döngü çalışıyordu. until döngüsünde ise, “kontrol_komutu” fail edene kadar döngü çalışır.

Yapısı şu şekildedir:

until kontrol_komutu
do
     #komutlar
done

Aşağıdaki kod örneği, “sayi” değişkeninin değeri “10” olmadıkça, başka bir deyişle “sayi = 10” ifadesi doğru olmadıkça, fail ettikçe çalışacak:

#! /bin/bash

#until döngüsü örneği:
#Aşağıdaki döngü, sayi değişkeninin değeri 10 olmadıkça çalışacaktır:

sayi=1

until [[ sayi -eq 10 ]]
do
	echo $sayi
	let sayi=sayi+1
	sleep 0.5
done

Çıktısı ise şöyle görünecektir:

[root@gnuadmin ShellScripting101]# ./20-until_dongusu_ornekleri.sh 
1
2
3
4
5
6
7
8
9

break ve continue Kullanımı

break, belirli bir koşul sağlandığında döngüyü kırıp çıkabilmenizi sağlar.

Aşağıdaki döngü, “/etc/passwd” dosyasında “sshd” kullanıcısını bulunca kırılacak:

[root@gnuadmin ShellScripting101]# cat 21-break_ve_continue.sh 
#! /bin/bash

#break örneği:
#Aşağıdaki döngü, "/etc/passwd" dosyasında "sshd" kullanıcısını bulunca kırılacak:

for user in $(cat /etc/passwd | cut -d ":" -f 1)
do
	echo $user kullanıcısını buldum
	if [[ "$user" == "sshd" ]]
	then
		break
	fi
done

Çıktı şu şekilde olacaktır:

Shell script break örneği
Shell script break örneği

continue ise, belirli bir koşul sağlandığında komutların çalışmamasını, döngünün bu cycle’ının pas geçilmesini sağlar.

Yukarıdaki döngüde, kullanıcılar arasından “root”un ekrana yazdırılmamasını sağlayalım:

#continue örneği:
#Aşağıdaki döngü, "/etc/passwd" dosyasında "root" kullanıcısını bulunca yazdırmayacak:

for user in $(cat /etc/passwd | cut -d ":" -f 1)
do
	if [[ "$user" == "root" ]]
	then
		continue
	else
		echo "$user kullanıcınısı buldum"
	fi
done

Çıktısı aşağıdaki gibidir:

bin kullanıcınısı buldum
daemon kullanıcınısı buldum
adm kullanıcınısı buldum
lp kullanıcınısı buldum
sync kullanıcınısı buldum
shutdown kullanıcınısı buldum
halt kullanıcınısı buldum
mail kullanıcınısı buldum
operator kullanıcınısı buldum
games kullanıcınısı buldum
ftp kullanıcınısı buldum
nobody kullanıcınısı buldum
systemd-network kullanıcınısı buldum
dbus kullanıcınısı buldum
polkitd kullanıcınısı buldum
sshd kullanıcınısı buldum
postfix kullanıcınısı buldum
mysql kullanıcınısı buldum
apache kullanıcınısı buldum