Shell Script #5 – Local ve Environment Variables

Daha önce değişkenler konusuna biraz değinmiştik. Bu yazıda ise local (yerel) ve environment (çevre) değişkenleri arasındaki farklılıklardan bahsedeceğiz.

Bu yazının sonunda, aşağıdaki ekran görüntüsünü anlar hâle gelmek istiyoruz:

Bash ortamında yerel değişkenler ve çevre değişkenleri

Bu yazıda kullanılan kod örnekierini GitHub’da bulabilirsiniz.

Local Variables

Yerel değişkenler, adından da tahmin edebileceğiniz üzere, yalnızca bulunduğunuz shell’de geçerli olan değişkenlerdir. Shell’imizde tanımlı tüm değişkenleri görmek için “set” komutunu kullanabiliriz. Aşağıdaki örneği inceleyelim:

[root@localhost ~]# echo $sezisli

[root@localhost ~]# sezisli=ali
[root@localhost ~]# echo $sezisli
ali
[root@localhost ~]# set | grep sezisli
sezisli=ali
[root@localhost ~]# printenv | grep sezisli
[root@localhost ~]# bash
[root@localhost ~]# echo $sezisli

[root@localhost ~]# set | grep sezisli
[root@localhost ~]# env | grep sezisli

Satır satır inceleyelim:

  1. “sezisli” değişkeninin değerini yazdırmak istiyoruz.
  2. Boş dönüyor.
  3. “sezisli” değişkenine “ali” değerini atıyoruz.
  4. “sezisli” değişkeninin değerini yazdırmak istiyoruz.
  5. “ali” yazdırılıyor.
  6. set ile değişkenlerimizi listeleyip “sezisli”yi grep’liyoruz.
  7. sezisli=ali yanıtı geliyor.
  8. printenv ile çevre değişkenlerimizi listeleyip “sezisli”yi grep’liyoruz. Yanıt yok.
  9. “bash” ile yeni bir shell açıyoruz.
  10. “sezisli” değişkeninin değerini yazdırmak istiyoruz.
  11. Boş dönüyor.
  12. set ile değişkenlerimizi listeleyip “sezisli”yi grep’liyoruz. Yanıt yok.
  13. printenv ile çevre değişkenlerimizi listeleyip “sezisli”yi grep’liyoruz. Yanıt yok.

printenv” nereden çıktı demeyin. Birazdan oraya da değineceğiz. Burada odaklanacağımız nokta, yeni bir shell’e geçtiğimizde değişkenin kaybolması.

Önemli bir nokta. Bu kısımda tanımladığımız değişkenler, sadece tanımlandıkları shell’de geçerli. Fakat o shell’in her noktasında geçerli. Shell’in içinde her yerden erişilebilir durumdalar. Bu açıdan bu değişkenlerin local değil, global olduğu da söylenir. Ciddi anlamda “local” arıyorsanız, bir de aşağıdaki konuya bakalım.

local Anahtar Kelimesi

local” anahtar kelimesi ile tanımlanan değişkenler, yalnızca tanımlandıkları alanda (scope) geçerli olur. “local“, yalnızca fonksiyonlar içinde kullanılabilir. Örneklemeye çalışalım:

#! /bin/bash
#Global değişken:
tarih=1928

ornek_fonksiyon(){
        #local anahtar kelimesi, yalnızca fonksiyon içinde kullanılabilir.
        #Burada, yine "tarih" isminde bir değişken tanımlıyoruz.
        #Sonrasında bu değeri ekrana yazıdırıyoruz:

        local tarih=1992
        echo "Beni fonksiyon yazdı. tarih=$tarih"
}

echo "Fonksiyon çağrılmadan önce tarih: $tarih"

ornek_fonksiyon

echo "Fonksiyon çağrıldıktan sonra tarih: $tarih"

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

local variable örneği
local variable örneği

Görüldüğü üzere, tarih değişkeninin değeri fonksiyon içinde “1992” yapılmış olmasına rağmen, fonksiyon dışına çıkıldığında bu değer geçerliliğini yitirmiş durumda.

Environment Variables

Local’in aksine, tüm shell’lerde geçerli olan değişkenler ise “çevre değişkenleri (environment variables)” olarak karşımıza çıkıyor. Bash’in Yapılandırma Dosyaları yazısında, varsayılan çevre değişkenlerinin hangi dosyalar tarafından ayarlandığından bahsetmiştik.

Shell’inizdeki tüm çevre değişkenlerini listelemek için “env” ya da “printenv” komutlarını kullanabilirsiniz:

[root@localhost ShellScripting101]# printenv
XDG_SESSION_ID=6
HOSTNAME=localhost.localdomain
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=10.2.2.2 54989 22
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/0
USER=root
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
MAIL=/var/spool/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
PWD=/root/projeler/ShellScripting101
LANG=tr_TR.UTF-8
MODULEPATH=/usr/share/Modules/modulefiles:/etc/modulefiles
LOADEDMODULES=
SELINUX_LEVEL_REQUESTED=
HISTCONTROL=ignoredups
GPG_TTY=/dev/pts/0
SHLVL=1
HOME=/root
LOGNAME=root
SSH_CONNECTION=10.2.2.2 54989 10.2.2.100 22
MODULESHOME=/usr/share/Modules
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/0
BASH_FUNC_module()=() {  eval `/usr/bin/modulecmd bash $*`
}
_=/usr/bin/printenv
OLDPWD=/root/projeler

Sıklıkla kullanacağımız bazı değişkenler görüyoruz:

  • HOME: Kullanıcının ev dizini.
  • HOSTNAME: Cihaz ismi.
  • LANG: Dil ayarı.
  • PATH: Çalıştırılabilir dosyaların aranacağı dizinler.
  • USER: Kullanıcı adı.
  • PWD: Şu an bulunulan dizin.
  • SHELL: Varsayılan olarak tanımlı shell.
  • MAIL: Kullanıcının e-posta kutusu.

export Komutu

Yukarıdaki örneklerden birinde, shell değiştirdiğimizde değişken değerinin kaybedildiğini görmüştük. Bu durumu engellemek mümkün. Tanımlanan değişkenin, subshell‘lerde de geçerli olabilmesi için “export” edilmesi gerekir.

Subshell’ler, parent’larında export edilmiş değişkenleri görebilir. Bu değişkenlerin değerlerini değiştirebilir. Fakat değişiklikler yalnızca subshell’lerde geçerli olur. Bir başka deyişle; subshell, parent’tan miras aldığı değişkeni tamamen değiştiremez. Subshell öldüğünde, değişken orijinal hâline geri döner. Örneği inceleyelim:

#! /bin/bash

#2 adet değişken tanımlıyoruz. Değişken tanımlarken = işaretinin sağ ve sol tarafında boşluk bulunmamalı:
semt=Buca
sehir=İzmir

#Değişkenleri export ediyoruz. Bu sayede bu değişkenler, subshell'ler tarafından da görülebilecektir.
#Aynı anda birden fazla değişkeni export edebiliriz.
#Şöyle de yapabilirdik: export semt=Buca (Atama ve export işlemi aynı anda)
export semt sehir

#Bir değişken daha oluşturuyoruz fakat export etmiyoruz:
test=geldi

#Bu satır, ekrana Buca / İzmir yazacak:
echo $semt / $sehir


#Buraya kadar olan kısım yalnızda export işlemi için. Sonrasında yeni bir shell'e geçin.
#Subshell'de semt ve sehir değişkenlerini görebileceksiniz. Fakat test değişkenini göremeyeceksiniz.

Yukarıdaki script’i, yeni bir shell forklamadan, başında “nokta” işareti ile çalıştırıyoruz ki export işlemi anlamlı olsun. Ayrıntılı bilgi için Shell Script’lerin Çalışma Mantığı‘nı okuyabilirsiniz:

[root@localhost ShellScripting101]# . ./6-export_ornegi.sh
Buca / İzmir
[root@localhost ShellScripting101]# bash
[root@localhost ShellScripting101]# echo $semt $sehir
Buca İzmir
[root@localhost ShellScripting101]# echo $test

[root@localhost ShellScripting101]# sehir=Ankara
[root@localhost ShellScripting101]# echo $sehir
Ankara
[root@localhost ShellScripting101]# exit
exit
[root@localhost ShellScripting101]# echo $sehir
İzmir
[root@localhost ShellScripting101]# echo $test
geldi

Satır satır inceleyelim:

  1. Script’imizi bulunduğumuz shell’de çalıştırıyoruz.
  2. Buca / İzmir çıktısını veriyor.
  3. Yeni bir subshell açıyoruz.
  4. Export edilmiş olan “semt” ve “sehir” değişkenlerinin değerleri yazdırılıyor. Sorun yok.
  5. Export edilmemiş “test” değişkeni ise boş dönüyor. Çünkü subshell’de böyle bir değişken tanımlamadık.
  6. Subshell içinde “sehir” değişkeninin değerini “Ankara” olarak güncelliyoruz. Ekrana Ankara yazabiliyor.
  7. Subshell’den çıkış yapıyoruz (exit).
  8. “sehir” değişkeninin değeri “İzmir” olarak karşımıza geliyor. Çünkü daha önce de dediğimiz gibi, subshell’ler parent’larından miras aldığı değişkenlere kalıcı müdahalede bulunamaz.
  9. Export edilmemiş “test” değişkeni ise parent shell’de hâlâ erişilebilir durumda.

unset Komutu

Tanımlanan değişkenleri temizlemek için de bir komutumuz var tabii ki. Export ettiğimiz bir değişkeni iptal etmek isteybiliriz. Tanımlanan bir değişkeni, ortamın devamına müdahale etmemek adına temizlemek isteyebiliriz.

Bash’in Yapılandırma Dosyaları yazısından hatırlarsanız, bazı ayar dosyalarında döngü değişkeni olarak “i” kullanılıyordu ve script sonunda bu değişken “unset” ediliyordu.

[root@localhost ShellScripting101]# unset semt sehir test
[root@localhost ShellScripting101]# echo $sehir

[root@localhost ShellScripting101]#