bash (bourne-again shell) sistemi kurulu olduğu sistem üzerindeki programları çağırabileceğiniz yetenekli bir arayüzdür, kabuktur.
shell (kabuk) ise temelde kullanıcıdan aldığı komutları işletim sistemi komutlarına dönüştüren bir programdır aslında.
bash en çok kullanılan komut satırı arayüzüdür. Linux, Unix, MacOS, Windows (subsystem olarak) işletim sistemlerinde genellikle bash varsayılan komut satırı arayüzüdür. (Not: MacOS’un Catalina isimli sürümüyle birlikte MAC’de varsayılan olarak artık bash yerine zsh kullanılmaya başlanmıştır)
bash 1989 yılında Brian Fox tarafından geliştirildi ve yoluna bir GNU projesi olarak devam ediyor. Geliştirmeler uzun bir süredir Chet Ramey tarafından sürdürülüyor. Özellikle gelişmeler için kendisinin sayfası takip edilebilir.
Bir programlama dilinde olması gereken bir çok özelliği de desteklediği için bash script bazen programlama dili olarakta lanse edilir.
Bash, string based output üretir. bash çok temiz ve basit kullanıma sahiptir. Basit olması onu kullanmayı kolaylaştırır. Bu sebeple çok popülerdir.
Bu yazıyı yazdığım tarih itibariyle yayında olan en son bash sürümü 5.0. Ancak her üretici farklı sürümler kullanıyor.
Bu yazı da Linux/Unix ‘i anlatmıyorum. Bash ve özelliklerinden bahsediyor olacağım.
# WSL
WSL (Windows Subystem for Linux) Windows 10’larda artık bir özellik olarak geliyor. Dilerseniz Control Panel özelliklerinden bunu kolaylıkla aktif edebilirsiniz.
Aktif ettikten sonra Microsoft Store’dan Ubuntu’tu indirerek bir alt sistem olarak Ubuntu’yu kullanabilirsiniz. Haliyle bash’i de kullanabilirsiniz.
# Shell, Bash Version
Kullandığınız kabuğun ne olduğunu görmek için genellikle $SHELL değişkenine bakabilirsiniz.
echo $SHELL
Kullandığınız bash sürümünü görmek için ise
bash --version
# Interactive & Non-Interactive Shell
Terminalinizi açtığınızda ekranınıza düşen ekran interactive shell, bu çalışma şekline ise interactive mode denilir.
Bash’in arkaplanda çalışma durumuna ise non-interactive shell, bu çalışma şekline ise non-interactive mode denilir.
Terminali açtığınızda bash , mevcut login session’ınızla açılır. exit komutunu girerek session’ı, prosesi sonlandırabilirsiniz.
# Prompt
bash’de interactive mode’da iken promptda göreceğiniz aşağıdaki karakterlerin anlamı:
$ : Komut girebileceğinizi belirtir, Yetkisiz bir kullanıcı ile komut çalıştırabilirsiniz.
# : Komut girilebileceğinizi belirtir. root yetkisiyle komut çalıştırabilirsiniz.
# Type of Command
Bash’de girilen ifade/komut bir keyword, bash built-in komutu ya da bir dosya olabilir.
Bash builtin girilen komutun bash’in içinde bir komut olduğunu belirtir.
Bir komutun ya da bir kelimenin bash built-in olup olmadığını type komutu ile görebilirsiniz.
type type type if type -t vim
compgen aracı bir bash builtin’dir. Bu araçtan yararlanarak tüm builtin’ler, keywordler, aliaslar, diğer komutları listelenebilir.
compgen -b comgen -k compgen -a compgen -c
#Help, –help, man
Help bir bash builtin komutudur. Bash builtin komutları hakkında bilgi verir.
help cd
Aşağıdaki komut ise tamamen farklıdır. Çünkü zip bir builtin komut değildir. Kendisine ait help sayfası vardır.
zip --help
Help komutunu, –help parametresini man page’lerle karıştırmamak gerekiyor. man page çok daha detaylı dokümanlardır.
man komutu builtin bir komut değildir. bash ‘in kendisinden bağımsızdır.
Her komutun help’i her komutunda man page’i olmak zorunluluğu yoktur.
Man page’lerle ilgili bilinmesi gereken temel şey bir komut, fonksiyon için man sayfasına baktığınızda sayfaların bölümlerden oluşuyor olmasıdır.
# Standard Input / Output / Error
Bash ‘i çalıştırdığınızda aşağıdaki 3 file description’ı otomatik olarak açılır.
Standard input (stdin) file descriptor 0 olarak tanımlanır.
Standard output (stdout) file descriptor 1 olarak tanımlanır.
Standard error (stderr) file descriptor 2 olarak tanımlanır.
Varsayılan olarak bu üç file descriptor terminala varsayılanda yönlendirilir.
# Redirectors
stdout için > ve >> operatörlerini kullanarak başka bir file description’a çıktıyı yönlendirebilirsiniz. stdout için 1 ifadesini kullanmanıza gerek yoktur.
> operatörü aynı isimde bir dosya varsa üzerine yazarken, >> operatörü yönlendiriliği dosyanın sonuna ekleme yapar.
echo "hello" > test.txt echo "world" >> test.txt
stderr için 2> ve 2>> operatörlerini kullanarak çıktıyı yönlendirebilirsiniz.
asdsad 2> hata.txt dasd 2>> hata.txt
stdout ve stderr ‘e aynı anda yönlendirmek için &> ve &>> operatörlerini kullanabilirsiniz. Ya da ard arda yönlendirerek kullanabilirsiniz.
ls &> liste.txt ls > liste.txt 2>hata.txt
stdout ve stderr çıktılarına /dev/null‘a yönlendirerek tamamen kurtulabilirsiniz.
cat test.txt > /dev/null cat test.txt 2> /dev/null
Dilerseniz çıktıyı yine stdout veya stderr’e yönlendirebilirsiniz.
cat test.txt >&1 cat test.txt >&2
stdin için < operatörünü kullanarak girdiyi ilgili komuta verebilirsiniz.
cat < liste.txt
# Pipe
| operatörüyle ifade edilir, unnamed pipe olarakta bilinir. Output’u alır ve standart input’a yönlendiren bir i/o redirector’dur.
ls | grep "test.txt"
Pipe’daki önemli nokta kendinden önceki komutun hata almadan output göndermesidir.
Pipe dediğimiz mekanizma kendinden önceki ve sonraki processlerin haberleşebilmesi için bir boru hattıyla kanal oluşturur.
# echo, printf
bash’de standart output’a argümanlarımızı yazdırmak için için echo ve printf built-in komutlarını kullanabiliriz.
Bu iki komut arasındaki fark; echo ekrana yazdırırken sonuna \n karakterini koyarken, printf \n karakterini koymaz. echo komutu eğerki -n parametresini alırsa printf gibi \n karakterini eklemez.
echo "hello" echo -n "hello" printf "hello\n"
printf komutunu echo komutuna neden tercih etmeniz gerektiği sorusuna, printf komutu içerisindeki format yapısı argüman alabilmektedir diyebiliriz. Örneğin
printf "%s %s\n" gokhan kesici printf "%s kesici\n" gokhan
printf komutu bir çok formatı desteklerken, aşağıdaki format’lar en önemlileri diyebiliriz:
Bir diğer format şeklide çıktının genişliğinin ayarlanabilir olmasıdır. – ise sola, + ise sağa yatık demektir.
printf "%+10s\n" gokhan
# Variable
Değişken tanımlama oldukça basit.
a=2 b='merhaba dunya'
Değişken değerini $degiskenadi şekinde alabiliyoruz.
echo $a echo $b
Önemli bir konu da değişken, = ve data arasında boşluğun olmaması gerektiğidir. Aksi durumda komut olarak algılanır ve hata alırsınız. Örneğin aşağıdaki ifadeler hatalıdır.
a = 3 b= 2 c =3
Değişkenleri string içinde kullanabiliriz. Bunun için çift tırnak kullanırız. Tek tırnak ile bu gerçekleşemez.
a=7 b="ugurlu sayim $a" echo $b
Bir diğer değişken çağırma yöntemi ise ${degiskenadi}. Aşağıdaki örnekteki kullanımlar için bu gösterim faydalı olacaktır. Bu kullanım ayrıca array başlığında bahsettiğimiz dizilerin çağrılması içinde kullanılmaktadır.
il=34 echo ${il}TR
# Environment Variables
Çevresel değişkenler kendi oluşturduğumuz tanımalar dışında, birden çok programın işletim sistemi üzerinde tanımlı sistem veya kullanıcı tabanlı değişkenleri kullanabilmesi için oluşturulmuştur.
Çevresel değişkenleri görebilmek için env veya printenv komutlarından birini kullanabilirsiniz.
printenv env
Interactive mod’da tanımladığınız bir değişkenin ortam değişkeni olarak listelendiğini yukarıdaki komutlardan da anlayabilirsiniz.
export ad=gokhan printenv | grep ad
Bir değişkeni kaldırmak için onu unset etmeniz yeterlidir.
unset ad printenv | grep ad
# export variable
Export komutu builtin bir komuttur. export komutuyla değişkeni child process’in görmesi sağlanabilir.
Export edilmiş değişkenleri görmek için aşağıdaki iki seçeneği de kullanabilirsiniz.
export export -p
Değişkeni export ederseniz child process değişken tanımını görecektir.
test="test" export test bash echo $test
export işlemini ayrıca declare komutu ile gerçekleştirebiliriz. declare başlığında konuya değindik.
# Prompt Variables
Prompt, linux da terminalizde size nerede, hangi dizinde hangi yetkilerle olduğunuzu gösterebilen kullanıcı dostu bir bilgidir.
Prompt’da nelerin gözükeceğini kendiniz belirleyebilirsiniz.
Bash ‘de PS1, PS2, PS3, PS4 olmak üzere 4 değişkende bu promptlar tutulur.
echo $PS1
PS2 ikincil promptur. Bu satır bitmediği devam ettiği durumlarda çıkan promptur. Varsayılan olarak > karakteridir.
echo "Hello >World
PS3 select komut gibi seçim yapılma durumlarında çıkan promptur.
select name in gokhan kesici; do echo $name; done 1)gokhan 2)kesici #?:1
PS4 ise debug durumlarda görüntülenen promptur. Defaultta + işaretidir.
set -x ls + ls dosya1.sh dosya2.sh
# Path Variable
Komutlar birer dosyadır ve bu komutlar dosyaların olduğu dizinlerde bulunurlar. Sırasıyla belirtilen komutların hangi dizinlerde araması gerektiğini PATH değişkeninde tanımlarız.
echo $PATH
Örneğin bir komutun çağrıldığında hangi dizinden çağrıldığını görmek için type veya which komutlarını kullanabilirsiniz.
which grep type grep
# Command Substitution
Bir komutun çıktısını kullanmak için iki farklı form bulunmaktadır.
Bunlardan ilki $(komut) formudur.
liste=$(ls) echo $liste
Diğer form ise `komut` formudur.
liste=`ls` echo $liste
# Here Document (heredoc)
Heredoc aslında bir çok programlama dilinde olan bir özelliktir.
<<Label şeklinde ifade edilen özel bir input yönlendirme şeklidir. Çok satırlı text girdisini solundaki komuta iletir.
cat << EOF merhaba dunya EOF
Text kısmı aslında ” “ içeren bir stringdir. Bu yüzden de değişken değerlerini gösterebiliriz.
degisken="dunya" cat << EOF merhaba $degisken EOF
Değişkeni göstermek istemiyorsak eğer <<‘label’ ifadesini kullanabiliriz. Aşağıdaki örnekte ” ” ifadesini ‘ ‘ dönüştürdüğümüz için değişken değeri gözükmeyecektir.
degisken="dunya" cat << 'EOF' merhaba $degisken EOF
# Comment
Özellike bash script yazarken kullanılan yorum satırlarını aşağıdaki gibi kullanabilirsiniz
#list root directory ls /root/
Çok satırlı yorum yazmak için bir tanım yok. Ancak farklı yöntemlerle çoklı satır oluşturulabiliyor.
Bunlar içerisinden ilki : ‘ ‘ ifadesi arasına yorum yazmaktır. : aslında bir komut olduğu için : ‘dan sonra boşluk bırakmanız gerekir.
: 'list root directory' ls /root/
Diğer bir seçenek ise marker kullanmaktır.
<<yorum1 list root directory yorum1 ls /root/
# Parent working directory, Change directory
Bulunduğunuz çalışma dizinini görüntülemek için:
pwd
Çalışma dizinini değiştirmek için:
cd /root/
Bir önceki çalışma dizinine dönmek için aşağıdaki kısayolu kullanabilirsiniz.
cd -
Bir üst dizinine çıkmak için:
cd ../
Mevcut dizini işaret etmek için:
cd ./liste.txt
# Tilde
~ karakterinin özel bir anlamı bulunur. Kullanıcının home dizinini işaret eder.
cd ~ cd ~gokhan
# pushd, popd
cd – komutunu bir önceki dizine gittiğinde bahsetmiştik. Ancak bu bir seviye ilerleyebiliyorduk.
pushd komutlarıyla çalışmak istediğimiz dizini DIR stack’e atıp, popd dediğimizde ise stack’den çıkarabiliriz.
Bilinemsi gereken en önemli şey pwd’nizin stack 0 olmasıdır.
pushd ‘de +1 -1 gibi argümanlarla stack’dekilerin konumlarını yukarı aşağı taşıyabilirsiniz. popd’de benzer argümanlarla ilgili argümanda sırasındaki dizin çıkartılabilir. Bu taşıma sırasında stack 0’daki dizin pwd’niz olacaktır.
pushd dir1 pushd dir2 pushd dir3 pushd +1 popd popd -1
dirs komutu ile stack’i görebilirsiniz. Stack 0’dan başlar ve dilerseniz +2 -2 gibi argümanlarla direkt stack’deki dizin görülebilir.
dirs -v dirs +2 # soldan sağa 3. eleman dirs -2 # sağdan sola 3. eleman
Stack kullanırken cd – komutunuzu kullanırsanız stack 0’ın değiştiğini göreceksiniz.
# Escaping
Bir çok programlama dilinde olduğu gibi kaçış operatörümüz \ ifadesidir.
echo 3 \> 2
# jobs
Bir komutu arka planda çalıştırmak için & işaretini kullanırız.
tail -f /var/log/messages &
Arkaplanda çalışan jobları listelemek jobs komutunu kullanırız.
jobs [1]+ Running tail -f /var/log/messages &
Çıktıdaki 1 ifadesi bash tarafından atanmış bir job numarasıdır. + ifadesi ise son çağrılan background job olduğunu gösterir. – ifadesi ise sondan 2. çağrılan job olduğunu gösterir.
Job’lar çeşitli statüleri bulunur. Örneğin bir üst örneğimizdeki 1 numaralı job hala çalışıyor durumdadır. Örneğin aşağıdaki komut ise arkaplanda atıldıktan sonra tamamlanan bir job’dır.
ls -l & [2]+ Done
Job bir şekilde hata alıp sonlanırsa exit statüsünde job’ımız görüntülenir.
lsl & [3]+ Exit 127
fg komutuyla arkaplanda çalışan bir job’ı arkaplandan çıkararak ön plana (foreground) getirebilirsiniz.
fg komutuna parametre vermezseniz jobs listesindeki son job’ı getirir. Job id’sini % ile belirterek direk ilgili background job çağrılabilir. % ifadesi yanında numara yerine string yer alıyorsa ilgili string’le başlayan komut öne getirilir. %? ‘de ise ilgili string’i içeren komut ön plana getirilir. %string ve %?string’ler birden fazla job ile eşleşirse belirsizlik söz konusu olduğu için öne hiç bir eşleşen job getirilmez. %+ son job’ı , %- ise sondan bir önceki job’ı öne getirir.
fg fg %1 fg %tail fg %?messages fg %+ fg %-
background’daki job’ların process id’sini görüntülemek için aşağıdaki iki parametreyi de kullanabilirsiniz.
jobs -l jobs -p
Ön planda çalışan bir prosesi suspend edip arka plana atayabiliriz. Bunun için CTRL+Z tuş kombinasyonuyla yapabilirsiniz. Suspend edilmiş proses jobs listesinde gözükür ve statüsü Stopped’dir.
tail -f /var/log/messages CTRL + Z [2]+ Stopped tail -f /var/log/messages
Stopped statüsündeki job’ı tekrar Running statüsüne getirmek için fg komutuyla ön plana getirebiliriz. Ya da arkaplanda running statüsünde devam etmesi için bg komutunu kullanabiliriz.
fg %2 bg %2
Bir job’ı öldürmek için kill komutunu kullanabiliriz. Kill olan proses terminated statüsündedir.
kill %2 [2]+ Terminated tail -f /var/log/messages
# History
Terminalde bash kabuğuna girdiğiniz komutlar kayıt altına alınır.
Kayıt yeri kullanıcının home dizinindeki .bash_history dosyasıdır. Aşağıdaki değişken ile de görme şansınız var.
echo $HISTFILE
.bash_history’de tutulan komutlar değerli olabilir. Çünkü parolanızı girmiş olabilirsiniz.
History ‘de ne kadar komutun tutulduğunu görmek için aşağıdaki değişken görüntlenir. Geçmişi history komutuyla silebilirsiniz.
echo $HISTFILESIZE history -c
Aslında tüm yapılandırmalar bashrc denilen initial script tarafından yapılandırılır.
Özellikle bir linux ile bir mac’deki bashrc dosyalarını incelerseniz yapılandırmaların farklı olduğunu göreceksiniz.
bashrc de bu değerleri değiştirerek veya bu değişkenleri değiştirerek istediğiniz değişikliği yapabilirsiniz.
export HISTFILESIZE=4000
History’deki bir komutu ! operatörüyle çağırabilirsiniz.
!! : son komut
!2 : ikinci komut
!-2 : sondan ikinci komut
!string : son kullanılan ve string ile başlayan komutu çalıştırır.
# profile, bash_profile, bashrc, bash_logout
# Alias
Girdiğiniz komutlar için kendi belirlediğiniz isimlerle alias ile değiştirebilirsiniz. alias diyerekte mevcut aliasları görebilirsiniz.
alias rcrsv='grep -R' alias
alias içinde alias tanımlanabilir.
alias myrc=rcrsv
# set, shopt
bash’deki özellikleri açıp kapayabilirsiniz.
Builtin olarak set komutuyla bunu gerçekleştirebilirsiniz. – işareti on + işareti ise off anlamına gelmektedir.
set -x set +x set -o noglob set +o noglob
bash 2.0 ile birlikte shopt komutu gelmiştir. Bu komut ile set ile benzer işlevi gören daha fazla ayar yapabileceğiniz builtin bir komuttur.
shopt -s globstar shopt -u globstar
# Hash commands
Komutlar sırasıyla PATH değişkeninde tanımlı dizinlere bakılarak aranır. Tekrar girdiğiniz bir komutu gidip tekrar aramamak için default da bash hash özelliği aktif gelir.
hash komutunu kullanarak hashlenmiş komutları görebilirsiniz. Ayrıca o komutu kaç kere çalıştırdığınızı da sayar.
hash table’i aşağıdaki komutla temizleyebilrsiniz.
hash -r
set komutunda hashall seçeneğini ile hash özelliğini açıp kapatabilirsiniz.
# Terminals
Terminal denilen şey kabuğa girdi gönderip çıktı alabildiğimiz bir arayüz.
Kernel içerisinde TTY (teletype) driver bulunmaktadır. Klavyeden girilenler kernel terminal emülatörle -ki biz buna console diyoruz- TTY driver’a iletilir. Buradan da ilgili process’e aktarılır.
ps komutunun çıktısında prosesisn tty’si ‘de belirtilir.
Diyelim ki gui’li kali gibi bir linux dağıtımı kullanıyoruz ve terminal programını kullanmak istiyoruz. Bu aslında console tipi değil user space terminal emülatör oluyor. Bunlara pseduo tty (PTY) deniliyor.
PTY , master ve slave adında iki kanaldan oluşuyor. Master, user space’deki terminal programınız, slave ise yine user space’deki prosesiniz.
Örneğin terminali ilk açtığınızda bash kabuğu aktif geliyor. Bu durumda ilk açılışta master echo $TERM komutununda çıktısındaki terminaliz (örneğin xterm), slave ise bash ‘dir.
ps komutunun çıktısında da görebileceğiniz pts ifadesi slave’i temsil eder. Aşağıdakine ek yeni bir terminal daha açarsanız pts/1 ifadesini göreceksiniz.
ps PID TTY TIME CMD 1253 pts/0 00:00:00 bash 3519 pts/0 00:00:00 tail 4550 pts/0 00:00:00 ps
Bağlı olunan tty character device’ı görmek için tty komutunu kullanabilirsiniz. Terminal ayar değişkliği için stty komutunu kullanabilirsiniz.
# Shell Command Precedence
Shell’e girilen komutlar belirli öncelik sırasına göre aranır. Sırasıyla aşağıdaki gibidir.
Executable programlar bahsettiğimiz üzere $PATH değişkeninde arar.
# builtin
Bir üstteki başlıkta öncelikte fonksiyonun builtin komutlardan önce geldiğini görebilirsiniz.
Diyelimki cd isimli komut bir bash builtin ve siz kendi cd isimli fonksiyonunuzu yazmak istiyorsunuz ve içerisinde yine cd komutunu kullanmak istiyorsunuz.
Bu gibi durumlarda komutun öncesine builtin ifadesini kullanmak yeterli olacaktır.
# Operators
assigment ( = )
arithmetic ( +, -, *, /, **, %, ++, –, +=, -=, *=, /=, %= )
logical ( !, &&, || )
bitwise (<<, >>, &, |, ~,^,&= )
comma (,)
# expr
bash’de aritmetik işlemlerinizi $((işlem )) şeklinde kullanmak yerine bash ‘de builtin olarak bulunmayan ancak linux’da var olan expr komutuyla da yapabilirsiniz.
expr 2 + 3 expr 2 \* 3 expr 2 \< 3 expre 4\/2
expr komutuyla bir string’in uzunluğunu öğrenebilirsiniz. Bunun yanı sıra help’inden görebileceğiniz bazı farklı opsiyonlarda kullanılabilmektedir.
expr length "gokhan"
# String Operators
String operatörleri ile bash’de diğer linux/unix komutlarını kullanmadan bizlere stringlerle işlemler yapmamızı sağlar.
String operatörleri { } içerisinde kullanılır.
degisken=gokhan echo ${#degisken} # 6 echo ${degisken:1} # okhan echo ${degisken:0} # gokhan echo ${degisken:0:2} # go echo ${degisken:0:-2} # gokh echo ${degisken: -2} # an echo ${degisken#g*} # okhan. eşleşen eğer stringin basıysa en kısa string pozisyonundan öncesini kaldırır. echo ${degisken##g*} # eşlesen eğer stringin basıysa en uzun string pozisyonundan öncesini kaldırır. echo ${degisken%n} # gokha . eşlesen eğer stringin sonuysa en kısa eşleşilen pozisyondan sonrasını kaldırır. echo ${degisken%%n} # esleşen eğer string sonuysa en uzun eşleşilenden pozisyondan sonrasını kaldırır. echo ${degisken/k/kk} # gokkhan . ilk eşleşileni değiştirir. echo ${degisken//k/kk} # gokhan . tüm eşleşilenleri değiştirir.
# Matching Operators
shopt çıktısında eğer extglob özelliği aktifse ki genelde aktifdir, diğer eşleşme operatörlerini kullanabiliriz.
ls * # wildcard ls *.sh # wildcard ls ?.sh # tek karakter ls [d1] # küme içerisindeki elemanları içerirse listeler. ls ?(a|b).pdf # Hiç veya bir tane a veya b içeren dosyaları listeler. (extglob) ls *(a|b).pdf # Hiç ya da çok fazla a veya b içerebilen dosyaları listeler. (extglob) ls +(a|b).pdf # Bir veya daha fazla a veya b içerebilen dosyaları listeler. (extglob) ls @(a|b).pdf # Bir a veya b dosyası içerebilen dosyaları listeler. (extglob) ls !(a|b).pdf # Bir a veya b 'yi içermeyen dosyaları listeler. (extglob)
# Condition
if ile birlikte condition’lar aşağıdaki şekillerde ve örnekler gibi kullanılabilir.
if command
if (command)
if [ condition ]
if [[ condition ]]
if (( condition ))
# if/else
Aşağıda if kullanımına en basit örnektir.
if [ 1 -gt 0 ] then echo "Buyuktur" elif [ 1 -eq 0 ] then echo "Esittir" else echo "Kucuktur" fi
if koşulu içerisinde komutta çalıştırılabilmektedir.
if [ $(ls -l 2> /dev/null) ] then echo "dogru" else echo "yanlis" fi
# Function
İki formda function oluşturulabilir.
İlk form function ifadesini kullanarak script içerisinde tanım yapmak ve fonksiyonu çağırmak.
function isim { echo gokhan; } isim
Diğer form ise function ifadesini kullanmadan fonksiyon oluşturmak.
isim() { echo gokhan; } isim
# return, exit
Bash’de return klasik programlama dillerinden biraz farklı kullanılıyor. Normalde bir fonksiyon return içeriyorsa return değeriyle döner.
Bash’de bir fonksiyon çağrıldığında son komutun return değeriyle döner ki başarılıysa bu 0, değilse 1-255 arasında bir değerdir.
return ifadesiyle bu değeri kendimiz belirleyebiliriz.
Benzer şekilde programdan çıkışımız statüsünü de exit ile belirleyebiliriz.
Aşağıdaki örnekte önce fonksiyondan 2 ile çıkılır, sonra programdan 3 ile çıkılır.
ornek () { echo "bu bir ornektir" return 2 } ornek echo $? exit 3
# Positional Parameters
Fonksiyona parametreleri iletebilir bu parametreleri pozisyona bağlı olarak kullanabilirsiniz.
isim() { echo $0; echo $1; echo $2; echo "Toplam $#"; echo "Parametreler [email protected]"; } isim gokhan kesici echo $1
# Scope
Bash’de script yazıyorsanız değişkenleriniz fonksiyon içerisinde olsa dahi global scope‘dur. Herhangi bir yerden erişilebilir.
isim() { echo gokhan; sayi=2; } isim echo $sayi
Yukarıdaki örnekteki sayi değişkenin global değilde local olmasını istiyorsanız local ifadesini kullanmanız gerekir.
isim() { echo gokhan; local sayi=2; } isim echo $sayi
Fonksiyon parametreleri localdir. Örneğin gidip bir script’e parametre verseniz bile bunu çağıramazsınız.
Örneğin aşağıdaki scriptimizi çağıralım. Fonksiyon $1 parametresini bilmeyecektir. Tek istisna $0 parametresidir. Bunu bilecektir.
function isim { echo $1; } isim ./test.sh gokhan
# for
Aşağıdaki for kullanımı syntax ‘ı görülebilir.
for name in list do statements can use $name done
Örnek kullanımlar:
for i in 1 2 3; do echo $i;done for i in {1..3}; do echo $i; done for i in {0..12..2}; do echo $i; done for i in $(seq 1 2 12); do echo $i; done for dir in $PATH; do echo $dir; done
C syntax’ına benzer aritmetik artan for dongüsü oluşturmak için aşağıdaki syntax kullanılabilir.
for (( i=1; i<=3; i++)); do echo $i;done
# while / until
while ifadesi koşul sağlanıncaya dek do içerisindeki ifadelerimizi çalıştırır. False durumunda dongüden çıkılır.
while kullanımına örnekler:
i=0; while [[ $i -lt 5 ]]; do echo $i; i=$(($i+1));done i=0; while [[ i -lt 5 ]]; do echo $i; i=$(($i+1));done i=0; while [[ $i -lt 5 ]]; do echo $i; i=$[$i+1];done while true; do tail -1f /var/log/syslog; sleep 3;done
until, while ile benzerdir. Koşul ifadesi doğru sağlanıncaya dek do ‘da tanımlı işlemi gerçekleştirir. True donülmesi durumunda döngü’den çıkılır.
until kullanımına örnek:
i=0; until [[ $i -gt 5 ]]; do echo $i; i=$(($i+1));done
# select
select ile menü yapısı oluşturulabilir. Örneğin:
select file in *;do cat $file; done
Select ifadesi PS3 prompt’unda yer alır. PS3 promptunun değişkenini değerini değiştirerek menüde istenileni sunabiliriz.
PS3='Seciminiz:'
# case
case ifadesini koşul ifadelerinde kullanabiliriz.
Syntax yapısı aşağıdaki gibidir.
case expression in pattern1) statements ;; pattern2) statements ;; *) statements ;; esac
Dikkat edilmesi gereken şey pattern’ler ;; özel karakteri ile sonlandırılmalıdır. Aksi durumda koşuldan hemen sonra koşulların sonlandırılma işlemi gerçekleşeceğinden diğer yazdıklarınız anlaşılmayarak syntax error alınır.
Örnek case kullanımı:
i=1 case $i in 1) echo "1";; 2) echo "2";; *) echo "0";; esac
# shift
Positional parameters bölümünde komutla birlikte yazılan argümanların aslında parametre olduğundan bahsetmiştik.
Bu parametrelerin bir diğer özelliği read-only olmasıdır. Örneğin aşağıdaki kullanım yanlıştır ve hata alınır.
isim() { 1=$2; echo $1; } isim gokhan kesici
Ancak shift komutuyla argümanlar belirtilen N sayısı kadar sola kaydırılır.
isim() { shift 3; echo $1; } isim gokhan kesici
# Commandline Options, getopts
Bash’de positional parametreler dışında – ifadesi ile opsiyon belirterek aşağıdaki gibi argümanları kullanabiliriz.
command [-options] args
Seçenekli argümanları shift komutundan yararlanarak case komutunuda kullanarak aşağıdaki gibi gerçekleştirebiliriz.
while [ -n "$(echo $1 | grep '-')" ];do case $1 in -h ) echo "help";; -c ) echo "command";; -d ) echo "del";; * ) echo "usage: gokhan [-h] [-c] [-d]";; esac shift done
Komut satırındakileri parse edebilmenin daha şık yolu getopts kullanmaktır. – ifadesi ile başlayan argümanlar birer opsiyon olarak otomatik parse edilir. getops her çağrıldığında bu opsiyonlar sırasıyla döner. Bu sebeple while döngüsü ile getopts birlikte aşağıdaki gibi kullanılır.
getopts optstring variable
Örneğin kendi oluşturduğumuz scanner.sh dosyamızı aşağıdaki gibi çağıralım.
# scanner.sh while getopts ":t:p:" o; do case "${o}" in t) t=${OPTARG} echo $t ;; p) p=${OPTARG} echo $p ;; ?) echo "yanlis opsiyon";; esac done ./scanner.sh -t 192.168.1.1 -p 443
# Arrays
Bash’de tek boyutlu diziler desteklenmektedir. Array’lere assign işlemini bir kaç şekilde gerçekleştirebilirsiniz. Aşağıdaki formlarda assigment işlemi yapılınca otomatik array oluşturulmuş olur.
b[2]=2 b[0]=gokhan
Diğer bir assign yapma şekli ise
b=([2]=2 [0]=gokhan)
Sıralı veya karışık bir şekilde dizileri assign etmek için aşağıdaki yöntemler kullanılabilir.
b=(gokhan kesici)
b=(gokhan [3]=kesici istanbul) # 0,3,4
Boş bir dizi oluşturmak için declare komutu kullanılabilir.
Dizi değişkeni çağırmak için ise süslü parantez ${ } kullanımı gereklidir ve dizinin diğer elemanları boş kalabilir.
echo ${b[1]} echo ${b} # index verilmezse b[0] demektir.
Array içerisindekileri görüntülemek için:
echo ${b[@]} echo ${b[*]}
Array boyutu öğrenmek için:
echo ${#b[@]} # 3
Array indexlerini öğrenmek için:
echo ${!b[@]} # 0 3 4
# declare
Variable’ları tanımlarken tipini deklare etmeden assign edebileceğimizi biliyoruz. declare komutu ile ise değişkenlerin tipini deklare edilebilriz.
declare ile birlikte kullanılan parametrelerin anlamları:
Örnekler:
declare -i a=1; a=one; echo $a; # son atanan değer bir integer olmadığından 0 olarak döner. declare -a a=3; echo ${a}; a[2]=5; echo ${a[2]}; declare -f; declare -f fonksiyon1; declare -F; declare -F fonksiyon1; declare -r a=1; (( a++ )) #hata alınır declare -x a; # değişkenimizi export edebilmemiz sağlanır.
# read
read komutu standart input veya bir dosyadan aldığı okuduğu her bir satırı değişkenlere atar.
read adiniz; echo $adiniz read -p "adiniz:" adiniz; # prompt read -sp "parola:" parola; # silent prompt read var1 var2 var3; echo $var3 $var2 $var1; # multiple variable
Eğer değişken adı verilmezse otomatik olarak $REPLY değişkene atama yapılır
read; echo $REPLY
Dosyadan satır satır okumak için:
while IFS= read line; do echo "test1 $line"; done <dosya1
# eval
eval yanına argüman olarak girdiğiniz değerleri tek bir string haline getirip tek komut olarak çalıştırır. evaluate’in kısaltması olan eval bir çok dilde bulunur.
list="ls -l | grep dosya"; eval $list eval "ls -l | grep dosya"
Command Substitution ile eval’i karıştırmamak gerekir. Yani aşağıdaki gibi bir kullanım hatalıdır.
list=$("ls -l | grep dosya");
eval’ın kullanıldığı yerlere dikkat edilmelidir. input validasyon yapılmadığında ve kullanıcıdan input alınan durumlarda kullanımı oldukça tehlikelidir.
# ps
ps bir bash builtin komutu değildir. Ancak yine de değinmeden olmayacaktır.
ps komutu System-V(unix), BSD, GNU stil dedikleri formatlarda opsiyonlar almayı destekler.
ps komutunda hiç bir parametre vermediğinizde çıktımız aşağıdaki gibi mevcut terminaldeki prosesleri listeler.
En basit çıktı olan bu formda
ps komutu bash komutu olmadığı için job numaralarıyla karşılaştırma yapamayacağından job id ‘leri göremeyiz.
ps -e veya ps -ax komutu ile tüm prosesleri listeleyebiliriz. Örneğin bu komutların sadece çıktılarında ufak farklılıklar vardır. Tüm prosesleri listelemenek için bir çok opsiyon vardır, ancak yine de en çok kullanılanlardan bazıları:
ps -e ps -ef ps ax ps -ax ps -A
Tüm proseslerin listelenmesi durumunda TTY kolonumuzda ? ifadesini görebilirsiniz. Bu bir terminale gerek duymayan bir proses, bir daemon olabilir.
Bir ps komutu çıktısındaki diğer kolonların anlamları şunlardır:
Filtreleme için sık kullanılan opsiyonlar:
Çıktıyı kontrol etmek için sık kullanılan opsiyonlar:
Thread’leri göstermek için sık kullanılan opsiyonlar: