Bash Script Öğrenme Notlarım — Uygulamalar

Semih Saydam
11 min readMay 5, 2024

--

Shell(Bash) Script öğrenirken aldığım notları sizlerle paylaşmaya devam ediyorum. Bu yazıda öğrendiklerimizi pekiştirmek ve hatırlamak adına uygulamaları inceleyeceğiz ^^

Uygulama 1

İlk uygulamamız argümanlarla ilgili olacak :

#!/bin/bash

echo "$0 programını çalıştırdınız"
echo "İlk argüman=$1"
echo "İkinci argüman=$2"
echo "Üçüncü argüman=$3"
echo "Bütün argümanlar=$*" # tüm argümanları yazdırma
echo "Argüman sayısı=$#" # argüman sayısını yazdırma
shift
echo "$0 programını çalıştırdınız"
echo "İlk argüman=$1"
echo "İkinci argüman=$2"
echo "Üçüncü argüman=$3"
echo "Bütün argümanlar=$*"
echo "Argüman sayısı=$#"

Burada kullanılan shift komutu sola doğru tüm argümanları kaydırır. Yani tüm argümanları bir öncekine atar, $2 olan $1'e gelir :

Gördüğünüz üzere $0 argümanı shift yaptığınız için kayboluyor, bir sola kayınca kayboluyor. 4 argüman varken, $0 kaybolduğu için 3 argümana düşüyoruz.

Uygulama 2

Burada da yine ls -l komutunu ve argümanları pekiştiriyoruz :

Burada bir shell script içinde ls komutuna argüman alıp, bu argüman ile ls komutunu işletiyoruz. /bin/ls şeklinde kullandığımıza dikkat edelim. Argüman olarak bir path alıp o path altındaki dosyaları görmüş oluyoruz.

Uygulama 3

#!/bin/bash

if [ $# -lt 1 ] # $# argüman sayısını veriyor. Yani hiç argüman girilmediyse :
then
echo "Lütfen dosya ismi giriniz!"
echo "Kullanım şekli=$0 yanına dosya ismi yaznan gerekir " # $0 script dosyasının ismini veriyor, bunun yanında dosya yazman gerek diye uyarıyoruz
fi
dosya=$1 #girilen değeri dosya değişkenine alıyoruz
# eğer bir dizin ise :
if [ -d "$dosya" ] # d directoryi, f regular file, e özel dosya(f olmayan), -w writable vb.
then
echo "$dosya bir klasördür."
elif [ -f "$dosya" ]
then
echo "$dosya normal bir dosyadır."
elif [ -e "$dosya" ]
then
echo "$dosya özel bir dosyadır."
else
if(($#==1)) # eğer argüman sayısı 1 ise bunu yaz diyoruz. Yukarıdaki ilk if'ten sonra buraya girmesin diye
then
echo "$dosya şeklinde bir dosya/dizin yoktur."
fi
fi

Buradaki yapılan uygulama ile argümanların nasıl yönetebileceğimizi ve if condition için alıştırmalar yapıyor olacağız :

Gördüğünüz gibi ilk if ile kullanıcı argüman girmiş mi girmemiş mi? Kontrol ediyoruz. Eğer girmişse bunu bir değişkene alıp, bu bir klasör mü? Dosya mı? vb. dosya parametrelerini de kullanarak farklı durumların if koşullarını yazıyoruz. Sağ tarafta da çalıştırdığımızda gördüğünüz üzere dosyayı, klasörü vb. tam yazdığımız şekliyle anlıyor.

Uygulama 4

Bu uygulamamızda bazı aritmetik işlemler yapacağız fakat bu aritmetik işlemleri yapmadan önce; Gelen argümanları Regex ile doğru formatta gelip gelmediğini kontrol edeceğiz :

#!/bin/bash

if [ $# -lt 2 ]
then
echo "Lütfen iki adet sayı giriniz"
echo "Kullanım şekli=$0 sayı1 sayı2"
exit
fi
x="$1"
y="$2"
if ! [[ "$x" =~ ^[[:blank:]]*[0-9]*[[:blank:]]*$ ]]
then
echo "Hatalı sayı=$x"
exit 1
fi
if ! [[ "$y" =~ ^[[:blank:]]*[0-9]*[[:blank:]]*$ ]]
then
echo "Hatalı sayı=$y"
exit 1
fi
topla=$((x+y))
fark=$((x-y))
carpma=$((x*y))
bolme=$((x/y))
echo "$x+$y = $topla"
echo "$x-$y = $fark"
echo "$x*$y = $carpma"
echo "$x/$y = $bolme"

Burada ilk if bloğu ile gelen argüman sayısının 2'den az olmaması gerektiğini kontrol ediyoruz. İkinci ve üçüncü if bloklarında “sıfır veya daha fazla boşlukla başlayıp, sıfır veya daha fazla sayı geldikten sonra, sıfır veya daha fazla boşluk olabilir” regex’ini yazdık. Yani siz sadece sayı girebilirsiniz ve başında sonunda boşluk girerseniz de sorun olmaz diyoruz. Eğer bu durumu sağlamayan bir durum varsa( if başındaki !) bu if bloğuna girecek ve hatalı sayı girdiğimizi söyleyip çıkacaktır. Eğer bu kontrollere takılmazsa da sayılarımız üzerinde aritmetik işlemlerini yapacaktır :

Uygulama 5

Bu uygulamada girilen sayının faktoriyelini alacağız. Bilgilerimizi pekiştirmeye çalışacağız.

#!/bin/bash

if [ $# -lt 1 ]
then
echo "Sayi Girmediniz"
echo "Kullanım şekli= $0 sayi"
exit 1
fi
sayi="$1"
if [[ "$sayi" =~ ^[[:blank:]]*[0-9]*[[:blank:]]*$ ]]
then
((i=1))
((faktoriyel=1))
while ((i<=$sayi))
do
((faktoriyel=faktoriyel*i)) #faktoriyel*=i
((i++))
done
else
echo "Hatali sayi= $sayi"
exit 1
fi
echo "$sayi faktoriyel = $faktoriyel"

Öncelikle ilk if sayesinde kullanıcının script’i çalıştırırken sayı girdiğinden emin oluyoruz. ./uygulama_5.sh şeklinde boş verirse bu if’e girip programı çalıştırmadan çıkacaktır.

Script çalıştırırken bir değer girildiğinden emin olduktan sonra bu girilen değeri “sayi” değişkenine atıyoruz. Ardından bu girilen değerin bir sayı olup olmadığını ikinci if bloğu ile garanti ediyoruz. Buraya girilen regex’i uygulama 4'te açıklamıştık, aynı regex ile girilen değerin sayı olduğunu garanti ediyoruz.

ifbloğu içinde bir while döngüsü kullanıp, faktoriyel hesabımızı yapıyoruz. Burada matematiksel ifadeler kullandığımız için (( )) şeklinde çift parantez içinde kullanıyoruz (aritmetik işlemler).

Böylelikle faktoriyel alan uygulamamızı da tamamlamış oluyoruz.

Uygulama 6

Bu uygulamamızda bir mini tahmin oyunu yapacağız. read komutu ile kullanıcıdan bir sayı alacağız ve random oluşturduğumuz sayı ile karşılaştıracağız. Büyük ve küçük yönlendirmeleriyle de sayıya ulaşmasını sağlayacağız. Sayıya eğer 6 tahminden daha az seferde ulaşırsa da tebrik edeceğiz. Şimdi kodumuzu yazalım ve beraber inceleyelim :

#!/bin/bash
random=$(( ($RANDOM%100)+1 ))
echo "1 ile 100 arasında (1 ve 100 dahil) bir sayı tuttum."
echo "Bil bakalım..."
echo -e "1 ile 100 arasında bir sayı giriniz:\c"
read tahmin
let tahminsayi=1
while ((tahmin!=random))
do
if ((tahmin>random))
then
echo "Daha küçük bir sayı giriniz"
elif ((tahmin<random))
then
echo "Daha büyük bir sayı giriniz"
fi
echo -e "1 ile 100 arasında bir sayı giriniz:\c"
read tahmin
let tahminsayisi++
done
echo "$tahminsayisi defada bildiniz"
if [ $tahminsayisi -lt 6 ]
then
echo "TEBRİKLER"
fi

RANDOM sistem değişkeni bize her çağrıldığında 0 ile 32767 arasında rastgele bir sayı döndürür. Bu sayıyı 100'e bölmenin kalanı (%100), 0 ile 99 arasında bir sayı verir. Ardından 1 eklenir, böylece sonuç 1 ile 100 arasında bir sayı olur. Sonuç olarak random=$(( ($RANDOM%100)+1 )) komutu ile 1 ile 100 arasında random bir sayı elde etmiş oluyoruz.

echo -e "1 ile 100 arasında bir sayı giriniz:\c"
read tahmin

Satırları hatırlarsınız ki; Bizden bir değer girmemizi istiyordu ve girdiğimiz bu değeri okuyarak bir değişkene atıyordu.

let tahminsayi=1 yaparak da tahmin sayısını tutabileceğimiz bir sayaç başlatıyoruz. let komutu, bash scriptlerinde aritmetik işlemler yapmak için kullanılır. let komutu, bir veya daha fazla aritmetik ifadeyi değerlendirmenizi sağlar. Örneğin :

let a=5
let "a += 1"
echo $a # Bu, '6' çıktısını verir
let count=0

while ((count < 5))
do
echo "count: $count"
let "count += 1"
done

gibi kullanımlarını görebilirsiniz.

Sonraki adımlarda while döngüsü ile random sayı ile tahminimiz örtüşene kadar dönüyoruz ve daha büyük/daha küçük yönlendirmelerini if koşulu ile sağlıyoruz. Bu döngü içinde de tabii ki kullanıcıya bilemediği durumda yeni tahmin şansı veriyoruz. Bildiği durumda da, tahmin sayısını bir if bloğu ile kontrol edip “6”dan az ise tebrik ediyoruz.

Burada neden if ((tahmin>random))ve if [ $tahminsayisi -lt 6 ] farklı yazılıyor diye sorabilirsiniz. İki if bloğunda da sayı karşılaştırılması yapıldığından aynı yazabilirdiniz fakat farklı yazımları görmeniz daha güzel olmuştur :) Kök nedenini merak edenler için de bu soruyu bize AI cevaplasın :

Gördüğünüz üzere köşeli parantezli kullanım genellikle string karşılaştırma ve dosya testlerinde kullanılır. Tabii bizim yaptığımız gibi sayısal karşılaştırmada da kullanılabilir. Artık mini oyunumuzu çalıştırıp sonucu görelim :

Uygulama 7

Bu uygulamada case yapısını hatırlamaya çalışacağız :)

#!/bin/bash

ay=$(date +%m)

case $ay in
02) echo "Bu ay 28 gündür. 4 yılda bir 29 gündür.";;
04|06|09|11) echo "Bu ay 30 gündür";;
*) echo "Bu ay 31 gündür";;
esac

Bildiğiniz üzere date komutu bugünün tarih ve saatini veriyor. date +%m de olduğunuz ayı; İki haneli olarak sayısal değerini verir. %m bir kalıptır ve aşağıda uygulayabileceğiniz diğer kalıpları da görebilirsiniz :

Bu kalıpları görünce aşağıdaki kullanım eminim size daha tanıdık gelmiştir :

Uygulamamıza tekrar odaklanırsak, burada case kullanımını hatırlıyoruz. Burada birden fazla uyan durumu | ile verebiliyor olmamıza dikkat edelim. Bunun yanında “diğer uyan durumlar” anlamında da * kullandığımızı hatırlayalım.

Uygulama 8

Bu uygulamada useradd komutu üzerinde durup kullanıcı oluşturma işlemi ile ilgili bir uygulama yapıyor olacağız. Diğer uygulamalara göre biraz uzun olacak, yolumuz uzun hadi yola çıkalım :)

useradd -m -d /home/semih -s /bin/bash -c 'SEMIH SAYDAM' semih Bu komutta gördüğünüz üzere kullanıcı eklerken bir sürü parametre veriyoruz. Bunları shell script yazarak almaya çalışacağız. -m ile “ ‘home’ altında kullanıcı için directory oluştursun mu?” yu veriyoruz. -s ile kullanacağı shell’in ne olacağını ve -c ile full isminin ne olacağını veriyoruz. Son olarak da login isminin “semih” olacağını veriyoruz. Buradaki ifadeyi elle yazmak yerine, shell script’in sorduğu sorularla buradaki ifadeyi oluşturmaya çalışacağız. Hadi kodumuzu inceleyelim :

#!/bin/bash

#isim
read -p "İsim giriniz:" isim digerisim
if [ -z $isim ]
then
echo "İsim giriniz"
exit 1
else
loginisim=$(echo $isim | tr [:upper:] [:lower:])
tamisim="$isim"
if [ ! -z $digerisim ]
then
tamisim="$isim $digerisim"
fi
fi

#soyisim
read -p "Soyisim giriniz:" soyisim digersoyisim
if [ -z $soyisim ]
then
echo "Soyisim giriniz"
exit 1
else
loginsoyisim=$(echo $soyisim | tr [:upper:] [:lower:])
tamsoyisim="$digersoyisim"
if [ ! -z $digersoyisim ]
then
tamsoyisim="$soyisim $digersoyisim"
fi
fi

#isim.soyisim
login=${loginisim}.${loginsoyisim}

#-s kısmı shell
echo -e "Shell olarak ksh mi bash mi istersiniz:\c"
read shell
if [ -z $shell ]
then
echo "Shell girmediniz"
exit 1
else
case "$shell" in
ksh) secilenshell=/bin/ksh;;
bash) secilenshell=/bin/bash;;
*) echo "Sadece ksh veya bash girebilirsiniz"; exit 1;;
esac
fi

#-m kısmı
read -p "Home directory oluşturulsun mu? (E/H):" evethayir
if [ -z $evethayir ]
then
echo "Tercih yapmadınız"
exit 1
else
case "$evethayir" in
E) dosyaolustur="-m";;
H) dosyaolustur=;;
*) echo "Sadece E veya H girebilirsiniz"; exit 1;;
esac
fi

echo "Girmeniz gereken komut:"
echo "-----------------------"
echo "sudo useradd $dosyaolustur -d /home/$login -s $secilenshell -c \"$tamisim $tamsoyisim\" $login"

Burada özetle kullanıcıya bir soru soracağız, bunu echo veya read ile yapabilirsiniz(ikisinin de örneği yukarıda var). Ardından kullanıcının cevaplarına göre useradd komutunu ekrana yazdıracağız. Kullanıcı da bu hazır komutu alıp terminaline yapıştırıp kullanıcı oluşturabilecek.

-z değişkenin uzunluğu 0 ise true döner. if [ -z $isim ] şeklinde kullanıyoruz ve eğer isim girilmediyse true dönüyor ve bu if bloğuna girmiş oluyor. “İsim girmediniz” gibi bir uyarı verip programı kapatıyor.

Elde etmek istediğimiz komutu incelerseniz; Küçük harflerle isim vb. yazdığımızı görebilirsiniz. Bu sebeple girilen değerler küçük harfle yazılmamışsa küçük harfe çevirmemiz gerekir. Bunun için loginisim=$(echo $isim | tr [:upper:] [:lower:]) bu komutu giriyoruz. | pipe ile bir komut çıktısını başka bir komuta girdi verebiliyorduk. echo’nun çıktısını tr’ye girdi olarak veriyoruz, böylelikle “isim” değişkeninden gelen değere tr komutu işletiyoruz. tr (translate) komutu, metin akışındaki karakterleri değiştirmek için kullanılır. Regex yazarak yapmak istediklerinizi belirtiyorsunuz [:upper:] [:lower:] yerine tr ‘A-Z’ ‘a-z’ de yazabilirdiniz yani.

Kullanıcının iki ismi yada iki soyismi olabilir diye de kodumuzu düzenliyoruz. Bu sebeple tamisim ve tamsoyisim değişkenlerini oluşturuyoruz.

login=${loginisim}.${loginsoyisim} kısmında “semih.saydam” gibi bir ifade etmek adına araya nokta koyarak değişken isimlerini birleştiriyoruz. ${variable} şeklinde süslü parantezleri kullanabildiğimizi ve bunun yanında da output=${ls -l} gibi komut işletip değerini değişkene kaydetme vb. işlemleri yapabildiğimizi unutmayalım.

*) echo “sadece E veya H girebilirsiniz”; exit 1;; kısmında case içinde birden fazla komut girmek istediğinizde ; kullanabildiğimize dikkat edelim. o case’i kapatırken de ;; kullanıyoruz. Tabii bunu alt alta komutları yazarak da yapabilirsiniz, alt satıra geçmek istemezseniz ; kullanabilirsiniz :

    pattern3)
# Birden fazla komut buraya yazılabilir
command5
command6
;;

pattern4)
#Tek satırda
command5; command6;;

Son olarak echo "sudo useradd $dosyaolustur -d /home/$login -s $secilenshell -c \"$tamisim $tamsoyisim\" $login" kısmında -c parametresinde çift tırnak kullanacağımız için ve echo komutunda hali hazırda çift tırnak içinde olduğumuzdan \"string\" şekilde escape character(\) kullanıyoruz. Script’imizi çalıştırdığımızda aşağıdaki gibi bir sonuç elde ediyoruz :

Uygulama 9

Bu uygulamada birikmiş dosyalarınızı tarihe göre nasıl klasörleyip yedekleyebilirsiniz ona bakacağız. Script’i çalıştırdığınız konumdaki dosyaları alıp, home directory’iniz altında o günün tarihi ve saatiyle bir klasör açıp(eşsiz olması için) o klasör içine kopyalar.

#!/bin/bash

yedekklasor="$HOME/yedek-$(date +%Y%m%d-%H%M%S)"

if [ ! -d yedekklasor ]
then
/bin/mkdir $yedekklasor
fi

for dosya in $(ls)
do
if [ -f $dosya ]
then
echo "$dosya kopyalanıyor"
/bin/cp -p $dosya $yedekklasor
fi
done

Script’imizde ilk olarak tarihe göre klasör yapısını kurgulamak için yedekklasor adında bir değişken oluşturuyoruz. Ardından -d parametresinin de yardımıyla, if [ ! -d yedekklasor ] bu klasörün(dizinin) olmadığı durumda yenisinin oluşturulması gerektiğini söylüyoruz. /bin/mkdir ile mkdir komutunu uyguluyoruz ve yeni bir klasör açıyoruz. ls mkdir cp vb. bunlar aslında bin klasörü altında olan uygulamalardı hatırlarsanız. Yedekleyeceğimiz klasörü hazırladık, şimdi dosyaları tek tek kopyalacağız. Bunu da for dosya in $(ls) döngüsü ile yapıyoruz. Bu döngüye göre, ls komutu çıktısında gelen tüm her şeyi dosya değişkenine atıyoruz ve döngü içerisinde döndürüyoruz. Biz sadece dosya’ları almak istediğimiz için if [ -f $dosya ] komutu ile ls çıktısından gelen verilerden dosya olanları kopyalamış oluyoruz :

Uygulama 10

Bu uygulamamızda iki sayıdan; Büyük olanı bulup ekrana yazdırıyor olacağız. Bunu yapmamızdaki asıl amaç function kullanımını hatırlamak :

#!/bin/bash

function buyuk {
if [ $1 -gt $2 ]
then
echo "$1"
else
echo "$2"
fi
}

if [ $# -lt 2 ]
then
echo "İki sayı girmelisiniz"
echo "Kullanım şekli: $0 <sayi1> <sayi2>"
exit 1
fi

x=$1
y=$2

if ! [[ "$x" =~ ^[[:blank:]]*[0-9]*[[:blank:]]*$ ]]
then
echo "Hatalı sayı=$x"
exit 1
fi
if ! [[ "$y" =~ ^[[:blank:]]*[0-9]*[[:blank:]]*$ ]]
then
echo "Hatalı sayı=$y"
exit 1
fi

max=$(buyuk $x $y)
echo "Büyük olan sayı: $max tır"

İlk olarak function içinde parametrelerden hangisi büyük diye bakıyoruz. Ardından iki sayı girmediyse diye bir if [ $# -lt 2 ] şeklinde bir kontrol sağlıyoruz. Her zamanki gibi, girdiği verilerin sayı olup olmadığını kontrol ettiğimiz içinde regex yazdığımız if koşullarını ekliyoruz. max=$(buyuk $x $y) kısmında hazırladığımız fonksiyonu çağırıyoruz ve büyük olan sayıyı buldurup; ekrana yazdırmış oluyoruz :

Uygularımızın sonuna geldik. Sonraki yazılarda görüşmek üzere; Sağlıklı ve mutlu günler diliyorum :)

--

--