Shell Script #4 – Bash’in Yapılandırma Dosyaları
Hayat kurtarmak için hazırda bekleyen shell’imiz, verdiğimiz komutları yorumluyor ve çalıştırıyor. Shell’imiz şu özelliklere sahip:
- Bir program çalıştırabiliyor. Harici komutlar (external commands) bunun örneği: ls, cat, ps gibi.
- Kendisi, önceden tanımlamış komutları çalıştırabiliyor. Dâhili komutlar (internal commands) bunun örneği: type, help, echo gibi.
- Aynı zamanda kendisi de bir programlama ortamı. Shell script’leri yazabiliyor ve bu scriptler içinde döngüler (for, while gibi), karar yapıları (if-else gibi) bunun örneği.
Bu açıdan bakarsak shell’imiz, gerçek anlamda bizim çalışma ortamımız. Black is the new gold. Bu yazıda, “bash” programının davranışlarını etkileyen ayar dosyalarından bahsedeceğiz.
Başlamadan önce tekrar vurgulamakta fayda görüyorum. “bash” shell’i için konuşuyoruz. Farklı shell’ler kullanıyorsanız farklı dosyalarla haşır neşir olmanız kuvvetle muhtemel.
Cihazınızda oturum açtığınız anda, bash bazı script’leri çalıştırır ve çalışma ortamınızı hazırlar. Bu script’leri 2 ana kategoriye ayırabiliriz:
Sistem Geneli Yapılandırma Dosyaları | Kullanıcı Bazlı Yapılandırma Dosyaları |
---|---|
/etc/profile | ~/.bash_profile |
/etc/bashrc | ~/.bashrc |
~/.bash_login | |
~/.profile |
Tabii ki bu dosyaların tamamı sisteminizde bulunmak zorunda değil. Bazılarını, farklı amaçlar için kendiniz de oluşturabilirsiniz. Şimdi bu dosyaların içeriklerine göz atalım ve amaçlarını anlamaya çalışalım.
/etc/profile Dosyası Nedir?
Bu dosya, yalnızda “root” kullanıcısının kontrolündedir. Sisteme login olan tüm kullanıcılar için çalıştırılır. “Sadece login shell’lerinde” çalıştırılır. Ne demek istediğimi örnekleyeceğim. Önce dosya içeriğini inceleyelim:
[root@localhost ~]# cat /etc/profile
# /etc/profile
# System wide environment and startup programs, for login setup
# Functions and aliases go in /etc/bashrc
# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.
pathmunge () {
case ":${PATH}:" in
*:"$1":*)
;;
*)
if [ "$2" = "after" ] ; then
PATH=$PATH:$1
else
PATH=$1:$PATH
fi
esac
}
if [ -x /usr/bin/id ]; then
if [ -z "$EUID" ]; then
# ksh workaround
EUID=`/usr/bin/id -u`
UID=`/usr/bin/id -ru`
fi
USER="`/usr/bin/id -un`"
LOGNAME=$USER
MAIL="/var/spool/mail/$USER"
fi
# Path manipulation
if [ "$EUID" = "0" ]; then
pathmunge /usr/sbin
pathmunge /usr/local/sbin
else
pathmunge /usr/local/sbin after
pathmunge /usr/sbin after
fi
HOSTNAME=`/usr/bin/hostname 2>/dev/null`
HISTSIZE=1000
if [ "$HISTCONTROL" = "ignorespace" ] ; then
export HISTCONTROL=ignoreboth
else
export HISTCONTROL=ignoredups
fi
export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL
# By default, we want umask to get set. This sets it for login shell
# Current threshold for system reserved uid/gids is 200
# You could check uidgid reservation validity in
# /usr/share/doc/setup-*/uidgid file
if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then
umask 002
else
umask 022
fi
for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do
if [ -r "$i" ]; then
if [ "${-#*i}" != "$-" ]; then
. "$i"
else
. "$i" >/dev/null
fi
fi
done
unset i
unset -f pathmunge
Kabaca göz attığımızda şunları görüyoruz:
- $PATH değişkeni tanımlanıyor.
- $USER, $LOGNAME, $MAIL değişkenleri tanımlanıyor.
- $HOSTNAME değişkeni tanımlanıyor.
- $HISTSIZE ile bash’in geçmişi ne kadar tutacağı tanımlanıyor.
- Varsayılan umask değeri ayarlanıyor.
- /etc/profile.d/ dizinindeki script’ler çalıştırılıyor.
Bu dosyayla ilgili dikkat etmemiz gereken bazı noktalar var:
- “Ne yaptığınızı bilmiyorsanız müdahale etmeyin.” uyarısını görüyoruz.
- Yeni bir ayar istiyorsak, bunu doğrudan bu dosya içine değil, /etc/profile.d/ dizini altında yeni bir dosyaya yazmalıyız.
- Fonksiyon ve alias‘ları buraya değil, /etc/bashrc altına tanımlamalıyız.
Gelelim login shell ile ne kast ettiğime. Bu script’in en altına bir komut ekleyeceğim: “echo ‘Merhaba. Beni buraya /etc/profile yazdı'”
Böylece bash her çalıştığında bu çıktıyı görmek isteriz değil mi?
Çok güzel. Gayet tatlı çalıştı. Çünkü bu bir “login shell”di. Oturum açabileceğimiz, bize kullanıcı adı – parola kombinasyonu soran bir shell. Benzer şekilde SSH yaptığımızda da bu mesajı göreceğiz.
Peki yeni bash’ler başlattığımızda ne olacak? Başlatacağımız yeni bash’ler, birer login shell olmayacağı için bu dosyayı çalıştırmayacak ve sonuç aşağıdaki gibi olacak:
Gördüğünüz gibi 1451 PID’li login shell’imiz altında 3 tane daha bash başlattık. Fakat bu başlangıçların hiçbirinde mesajımızı göremedik.
Login shell ve non-login shell arasındaki farkı daha iyi, daha detaylı anlamak isterseniz burası iyi gelebilir.
/etc/bashrc Dosyası Nedir?
profile dosyası, fonksiyon ve alias’lar için bizi bu dosyaya yönlendirmişti hatırlarsanız. İçeriğine bir göz atalım:
[root@localhost ~]# cat /etc/bashrc
# /etc/bashrc
# System wide functions and aliases
# Environment stuff goes in /etc/profile
# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.
# are we an interactive shell?
if [ "$PS1" ]; then
if [ -z "$PROMPT_COMMAND" ]; then
case $TERM in
xterm*|vte*)
if [ -e /etc/sysconfig/bash-prompt-xterm ]; then
PROMPT_COMMAND=/etc/sysconfig/bash-prompt-xterm
elif [ "${VTE_VERSION:-0}" -ge 3405 ]; then
PROMPT_COMMAND="__vte_prompt_command"
else
PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
fi
;;
screen*)
if [ -e /etc/sysconfig/bash-prompt-screen ]; then
PROMPT_COMMAND=/etc/sysconfig/bash-prompt-screen
else
PROMPT_COMMAND='printf "\033k%s@%s:%s\033\\" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
fi
;;
*)
[ -e /etc/sysconfig/bash-prompt-default ] && PROMPT_COMMAND=/etc/sysconfig/bash-prompt-default
;;
esac
fi
# Turn on parallel history
shopt -s histappend
history -a
# Turn on checkwinsize
shopt -s checkwinsize
[ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "
# You might want to have e.g. tty in prompt (e.g. more virtual machines)
# and console windows
# If you want to do so, just add e.g.
# if [ "$PS1" ]; then
# PS1="[\u@\h:\l \W]\\$ "
# fi
# to your custom modification shell script in /etc/profile.d/ directory
fi
if ! shopt -q login_shell ; then # We're not a login shell
# Need to redefine pathmunge, it get's undefined at the end of /etc/profile
pathmunge () {
case ":${PATH}:" in
*:"$1":*)
;;
*)
if [ "$2" = "after" ] ; then
PATH=$PATH:$1
else
PATH=$1:$PATH
fi
esac
}
# By default, we want umask to get set. This sets it for non-login shell.
# Current threshold for system reserved uid/gids is 200
# You could check uidgid reservation validity in
# /usr/share/doc/setup-*/uidgid file
if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then
umask 002
else
umask 022
fi
SHELL=/bin/bash
# Only display echos from profile.d scripts if we are no login shell
# and interactive - otherwise just process them to set envvars
for i in /etc/profile.d/*.sh; do
if [ -r "$i" ]; then
if [ "$PS1" ]; then
. "$i"
else
. "$i" >/dev/null
fi
fi
done
unset i
unset -f pathmunge
fi
# vim:ts=4:sw=4
alias pro='. /root/proxy.sh'
Karşımıza şunlar geliyor:
- Sistem genelinde kullanılan fonksiyon ve alias’lar burada yer alıyor.
- Çevre değişkenleri (environment variables) ile ilgili işlerin /etc/profile’a gitmesi gerektiği belirtilmiş.
- Ve yine; mümkünse elinizi sürmeyin ve ayarlarınızı, /etc/profile.d/ altına oluşturacağınız yeni script’lerde yapın uyarısı verilmiş.
- Shell prompt’umuzla ilgili bazı ayarlar yapılmış.
- PATH ve umask için yine bir değer ataması var. Çünkü /etc/profile ile login shell’lerinde bu ayarları yapmıştık. Non-login shell’de ise burada yazanlar geçerli olacak.
- En altta da, proxy değiştirmek için kullandığım script’im için bir alias tanımlamışım. Böylece her “pro” yazdığımda, bash gidip benim hazırladığım proxy script’ini çalıştıracak.
.bash_profile ve .bashrc Dosyaları Nedir?
Kullanıcı oturum açtığında, bu dosyalardan biri çalıştırılarak kullanıcı ortamını hazırlar.
“.bash_profile” dosyası login shell’lerde çalışırken, “.bashrc” dosyası non-login shell’lerde çalışır. Bu iki dosya da, kullanıcının ev dizininde bulunur.
.bash_profile Dosyasının İçeriği
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin
export PATH
export GPG_TTY=$(tty)
Alias ve fonksiyonların login olduğumuz anda gelebilmesi için “.bashrc” dosyasının varlığı kontrol edilmiş. Sonrasında bu script, bu shell’de geçerli olacak şekilde çalıştırılmış. Baştaki noktanın olayı bu.
Her kullanıcının ev dizininin farklı olması beklendiği için, burada PATH değişkenine kullanıcının ev dizini altında bulunması muhtemel “bin” dizini de eklenmiş. Bu ayarı “/etc/profile” altında yapsaydık, tüm kullanıcılar path’inde aynı ev dizinini görürdü.
Son olarak GitHub’da verified commit yapabilmek için “GPG_TTY” değişkenini ayarlamışım.
.bashrc Dosyasının İçeriği
# .bashrc
# User specific aliases and functions
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
Tanımlanmış 3 tane alias görüyoruz. rm, cp ve mv programlarının tamamı; varsayılan olarak “-i” parametresiyle başlatılmış. Mevzular böyle işte arkadaşlar. “Abi RHEL ve CentOS’ta silmeden önce silinsin mi diye soruyor. Diğer dağıtımlar sormuyor. Dağıtım farkı işte.” demeden önce, açıp varsayılan olarak tanımlanmış alias’lara bir bakmakta fayda var. Bu dağıtım, bu dosya içinde bu alias’ları tanımlamış. Yoksa rm hâlâ aynı rm. Değişen bir şey yok.
Bu dosyanın da “/etc/bashrc” dosyasını çağırdığını görüyoruz. Bu bağlantılar çok önemli. Globaldeki her şeyi alıyoruz. Üzerine şahsi değişikliklerimizi yapıyoruz. Eğer globaldeki ayarları almazsak shell’imiz sağlıklı çalışmayacaktır.
.bash_login Dosyası Nedir?
Login olduğumuzda profile dosyaları çalıştırıyordu. “/etc/profile” sistem geneli için, “~/.bash_profile” ise kullanıcıya özel. “.bash_login” dosyası ise, “.bash_profile” dosyasının bulunmadığı zamanlarda çalıştırılan bir script. Kullanıcı login olduğunda yapılacak tanımlamalar ve çalıştırılacak programları içerir. Muhtemelen sisteminizde böyle bir dosya yoktur. Bunun yerine “.bash_profile” oluşturulmuştur.
.profile Dosyası Nedir?
“.bash_profile” ve “.bash_login” dosyalarının bulunmadığı zamanlarda çalıştırılır. Amacı aynıdır. Muhtemelen bu dosya da sisteminizde bulunmuyordur.
Shell’imizi Biraz Kişiselleştirelim
Oturum açtığımızda sistemimizin bizi karşılamasını istiyoruz. Bu durum, yalnızca bizim kullanıcımız için geçerli olsun.
Böyle bir durumda “/etc” altındaki dosyalardan uzak duracağız. Çünkü o dosyalardaki ayarlar sistem geneline uygulanıyor. Bu karşılama durumu, login olduğumuzda gerçekleşsin istiyoruz. İlgileneceğimiz dosya “~/.bash_profile” olacak:
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin
export PATH
export GPG_TTY=$(tty)
#Karşılama kısmımız burada başlıyor:
echo Hoş geldin $USER, $HOSTNAME cihazına bağlandın.
echo Bugün: $(date)
echo "Kullandığın DNS'ler:"
cat /etc/resolv.conf | grep nameserver | cut -d " " -f 2
“Karşılama kısmımız burada başlıyor:” satırının altından itibaren kodlarımı yazdım ve kaydettim. Bir sonraki login’de durum şuna dönüşüyor:
Kodun açıklamalı hâlini GitHub’daki repo’da bulabilirsiniz (4-bash_profile_ornegi.sh).
Dikkat ettiyseniz, yeni açılan shell’lerde karşılama mesajımızı göremiyoruz. Çünkü bu shell’ler bir login shell değil.
.bashrc Altına Alias Tanımlama
Bir de alias tanımlayalım ve kullanmayı deneyelim. Çalışmayacak. Baştan söyleyeyim.
Alias’larımızı “.bashrc” altına tanımlıyorduk:
# .bashrc
# User specific aliases and functions
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
#Buraya yeni bir alias tanımlıyorum:
alias ls='ls -alhi'
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
“Buraya yeni bir alias tanımlıyorum:” satırının altında, ls için bir alias tanımlamışım.
Şimdi aşağıdaki çıktıyı ve ekran görüntüsünü inceleyelim:
[root@localhost ~]# type ls
ls `ls --color=auto' için takma addır
[root@localhost ~]# ls
bashscript degiskenler.sh projeler proxy.sh
[root@localhost ~]# source .bashrc
[root@localhost ~]# type ls
ls `ls -alhi' için takma addır
[root@localhost ~]# ls
toplam 72K
33582145 dr-xr-x---. 7 root root 4,0K Oca 31 19:14 .
64 dr-xr-xr-x. 17 root root 224 Oca 26 14:59 ..
33582149 -rw-------. 1 root root 20K Oca 31 19:15 .bash_history
33582196 -rw-r--r--. 1 root root 17 Ara 16 21:08 .bash_logout
34705792 -rw-r--r--. 1 root root 200 Oca 31 19:13 .bash_profile
33582201 -rw-r--r--. 1 root root 236 Oca 31 19:14 .bashrc
775334 drwxr-xr-x. 2 root root 88 Oca 22 22:06 bashscript
34022782 -rw-r--r--. 1 root root 100 Ara 29 2013 .cshrc
33582200 -rwxr--r--. 1 root root 70 Ara 16 21:41 degiskenler.sh
33582202 -rw-r--r--. 1 root root 154 Oca 30 17:43 .gitconfig
33865371 -rw-------. 1 root root 71 Oca 30 18:16 .git-credentials
50671788 drwx------. 3 root root 257 Oca 30 18:16 .gnupg
33582199 -rw-------. 1 root root 86 Oca 29 14:17 .lesshst
33987585 -rw-------. 1 root root 476 Ara 5 16:27 .mysql_history
51139467 drwxr-----. 3 root root 19 Ara 5 16:05 .pki
33582188 drwxr-xr-x. 5 root root 82 Oca 30 17:46 projeler
33627844 -rwxr--r--. 1 root root 509 Oca 29 13:20 proxy.sh
34705992 -rw-------. 1 root root 44 Oca 29 16:48 .python_history
33582197 drwx------. 2 root root 57 Oca 26 03:14 .ssh
34022783 -rw-r--r--. 1 root root 129 Ara 29 2013 .tcshrc
Satır satır inceleyelim:
- “ls” nedir diye sorduk. “ls –color=auto” için takma addır (alias) yanıtını aldık. Sistem üzerinde ls programının renkli çalışmasını sağlayan alias budur. Yoksa dizinler mavi olacakmış falan, böyle bir şey yok. Her “ls” yazdığımızda – tıpkı rm -i örneğinde olduğu gibi – böyle davranması için hazırlanmış.
- ls çalıştırıyorum. Bildiğimiz ls çıktısı veriyor. Fakat ben “.bashrc” altında alias tanımladım. Neden benim tanımladığım alias yok? Neden benim belirttiğim parametrelerle çalışmadı? Çünkü bu yapılandırma dosyaları, bash ilk çalıştırıldığında çalışır. Hâli hazırda açık olan bir programın yapılandırmasını değiştirmek anlamsızdır. Çünkü bash, bu dosyaları çoktan okudu ve bitirdi. Peki değişiklik yaptığımızda ne olacak?
- “Kapatıp aç”, “Oturumu kapat tekrar gir” gibi şeyler duyabilirsiniz. Lazım olduğu yerler belki vardır fakat burası o anlardan biri değil. Burada yardımımıza “source” koşuyor. “source” komutunun amacı, bir dosyadaki ayarları “şu an bulunduğunuz shell’e” okumaktır. Verdiğiniz ayar script’ini kullanarak shell’inizi tekrar günceller. Bunun yerine “. .bashrc” de kullanabilirdik.
- type, bizim alias’ımızı gösteriyor.
- ls, alias’ta belirttiğimiz gibi “ls -alhi” çalıştırıyor.
Harika!