07- Internal ve External Komutlar
Önceki yazılarımda sıklıkla "komut" ve "program" kelimelerini kullandığımı göreceksiniz. Bu ikisi arasındaki temel fark şudur: Komut, CLI'a yazıp Enter'a basarak gönderdiğiniz satırın tamamıdır. Program ise, yazdığınız komutlar içerisinde kullandığınız, size yardımcı olan binary dosyalardır.
Fakat Bash'te, yalnızca bu binary'lerden faydalanmayız. Bash'in kendisi de bir programdır ve her programda olduğu gibi, Bash içinde de birçok "yerleşik" fonksiyon vardır. Bash'te bunlara Shell builtin ya da Bash builtin deriz. Bu özellikler, Bash içerisine zaten eklenmiş durumdadır ve harici bir programa ihtiyaç duymaz.
Internal ve External Komutlar
Internal ve external komutlar ile ilgili ayrıca yazdığım bir yazı var. Dilerseniz buradan inceleyebilirsiniz.
Bu komutların farkını incelemeye başlamadan önce, birkaç farklı Linux komutundan bahsedelim. Bu araçlar, aradaki farkı anlamamıza yardımcı olacak.
which
which programı, bir komutun yerini tespit etmenizi sağlar. Örneğin:
ali@ubuntu24:~$ which ls
/usr/bin/ls
ali@ubuntu24:~$ which pwd
/usr/bin/pwd
ali@ubuntu24:~$ which cd
ali@ubuntu24:~$
Biz daha önce ls, pwd ve cd komutlarını kullandık. Ama hangi ls, hangi pwd, hangi cd? Bunları sorduğumuzda, farklı yanıtlar aldık. Örneğin, ls ve pwd için, "/usr/bin" dizini altında yer alan bazı dosyalar gösterildi. Fakat cd için hiçbir çıktı gelmedi.
which Çıktısını Yorumlama
Yukarıdaki örneğe bakıldığında; sanki ls ve pwd external komut, cd ise bir internal komutmuş gibi düşünebilirsiniz. Fakat internal ve external komut farkını anlamak için which çıktısı yeterli değildir.
file
file komutu, bir dosyanın tipini görmemizi sağlar. Bunu, ilgili dosyanın header bilgilerine bakarak gerçekleştirir. Dosyanın uzantısının hiçbir önemi yoktur.
Linux'ta Dosya Uzantısı
Yaygın olarak kullanılan Linux dosya sistemlerinde, dosya uzantılarının bir önemi yoktur. Bir metin dosyasının uzantısını .FLAC yapmanız ya da bir PDF belgesinin uzantısı .PNG olarak değiştirmeniz, anlam ifade etmez. Yalnızca grafik arayüz kullanan dağıtımlarda, bazı uzantılı dosyaları varsayılan olarak bazı programlarla açmak gibi bir ayar yapabilirsiniz. Ancak burada uzantının amacı, dosyaları kategorize etmekten başka bir şey değildir. Başka bir deyişle, "Linkin Park - With You.docx" gibi bir müzik dosyasını alıp, yine medya oynatıcınız ile açabilirsiniz. Dosyanın uzantısı, dosyanın içeriğini değiştirmez.
Birkaç dosya için file komutunu deneyelim:
ali@ubuntu24:~$ ls
evraklar kopya1 projeler 'tatil fotoğrafları'
ali@ubuntu24:~$ file kopya1
kopya1: ASCII text
ali@ubuntu24:~$ file projeler/
projeler/: directory
ali@ubuntu24:~$ file /usr/bin/ls
/usr/bin/ls: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=3eca7e3905b37d48cf0a88b576faa7b95cc3097b, for GNU/Linux 3.2.0, stripped
ali@ubuntu24:~$ file /usr/bin/pwd
/usr/bin/pwd: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=29d2c22122c87ddaaf9cecca0e519a312c5be56a, for GNU/Linux 3.2.0, stripped
ali@ubuntu24:~$
Ev dizinimizin içeriğini listeledik. Daha önceden oluşturduğumuz "kopya1" dosyasını sorguladık ve "ASCII text" olduğunu gördük. "projeler" için ise bir "dizin" olduğu bilgisi verildi. Yukarıdaki örnekte which ile elde ettiğimiz dosya yollarını (path) sorguladık ve bunların "ELF 64-bit LSB pie executable..." dosyalar olduğunu gördük. Belli ki bunlar birer program.
Absolute ve Relative Path
Gördüğnüz gibi, zaten ev dizinimizde file çalıştırdığımız için "kopya1" ve "projeler" için relative path kullandık. "/usr/bin" altındaki dosyaları sorgulamak için ise absolute path kullandık.
type
Internal ve external komut konusunda en büyük yardımcımız, type komutu olacaktır. type, komut ile ilgili bilgi gösteren bir Bash yerleşiğidir (builtin).
Aşağıdaki örneği inceleyin:
ali@ubuntu24:~$ which type
ali@ubuntu24:~$ type which
which is /usr/bin/which
ali@ubuntu24:~$ type ls
ls is aliased to `ls --color=auto'
ali@ubuntu24:~$ type cd
cd is a shell builtin
ali@ubuntu24:~$ type pwd
pwd is a shell builtin
ali@ubuntu24:~$ type echo
echo is a shell builtin
ali@ubuntu24:~$ type mkdir
mkdir is /usr/bin/mkdir
ali@ubuntu24:~$ type cp
cp is /usr/bin/cp
ali@ubuntu24:~$ type mv
mv is /usr/bin/mv
ali@ubuntu24:~$
which type ile, type komutunun yerini tespit etmeyi denedik. Hiçbir dosya çıkmadı. type which ile ise, which komutunun tipini sorduk ve "which is /usr/bin/which" yanıtını aldık. Yani Bash, biz ona which yazdığımızda, gidip /usr/bin/which path'inde bulunan programı çalıştıracak.
ls için ise, "ls is aliased to "ls '--color=auto'" yanıtını aldık. "alias" konusuna ileride değineceğiz. Fakat aslında biz her ls yazdığımızda, aslında ls --color=auto çalıştırıyormuşuz. Demek ki bu yüzden, bizim dosyalarımız ve dizinlerimiz listelendiğinde, farklı renklerde görünüyormuş. Wow.
cd, pwd, echo için ise "shelll builtin" ifadesini görüyoruz. Demek ki bu komutların hiçbiri, harici program olarak çalıştırılmıyormuş. Aslında bunlar, Bash'in kendi özellikleriymiş.
pwd
Biraz önce which kısmında pwd için "/usr/bin/pwd" ifadesini görmüştük. Böyle bir program vardı. Fakat type ile sorduğumuzda, bir shell builtin olarak göründü. Bu, kafa karışıklığına sebep olmuş olabilir. pwd diye bir program gerçekten de var. Fakat aynı isimli bir Bash yerleşiği de var. Ve Bash, biz ona pwd yazdığımızda, gidip "/usr/bin/pwd" çalıştırmıyor. Kendi yerleşik "pwd" fonksiyonunu çalıştırıyor. Nereden biliyoruz? Çünkü type ile bunu sorduğumuzda, bize shell builtin yanıtını verdi.
hashed
type ile sorduğunuz bir soruya cevaben "hashed" yanıtını alabilirsiniz. Problem yok. Bir sonraki bölümde, bunun ne olduğunu göreceğiz.
Internal Komut Nedir?
Internal komutlar, shell'inize eklenmiş komutlardır. Harici program değillerdir. Bu komutlar, shell'inize ait işlevlerdir.
Bash, yazılan komutu önce kendisi anlamaya çalışır. Eğer yazılan komut, bir shell builtin ise, ilgili fonksiyonunu çalıştırır. Yazılan komutun, Bash içerisinde bir karşılığı yoksa, external olma ihtimali ele alınır.
External Komut Nedir?
External komutlar, adından da anlaşılabileceği üzere, shell'inizin ne olduğunu bilmediği, ancak gidip çalıştırdığı komutlardır. External komutlar, sisteminizdeki programlardır. Bu programlar derlenmiş kodlar olabileceği gibi, script'ler de (Phyton, Bash, PHP gibi) olabilir.
Peki bu programların nerede olacağını Bash nasıl biliyor? Bunun da çok basit bir yanıtı var: $PATH.
PATH Çevre Değişkeni
"$PATH" bir çevre değişkenidir (environment variable). Bu konuya, ilerleyen bölümlerde değineceğiz. Bu değişkenin değerini görmek için echo $PATH komutunu kullanabiliriz:
ali@ubuntu24:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
ali@ubuntu24:~$
Yukarıdaki çıktıdan anlaşılacağı üzere, Bash ona bir komut verdiğimizde, bunu sırasıyla "/usr/local/sbin", "/usr/local/bin"... dizinlerinde arayacakmış.
Önce Internal
Bash her zaman, öncelikli olarak builtin'lerine bakar. Bunun en açık örneğini, pwd kısmında gördük. pwd, "/usr/bin" dizini içerisinde yer alıyordu. Yukarıda göreceğiniz üzere, bu path zaten bizim "$PATH" değişkenimizde var. Fakat yine de, type pwd dediğimiz zaman "shell builtin" yanıtını alıyoruz. Demek ki Bash, bir komut kendi builtin'i olduğunda, onu external bir yerde aramıyor ve direkt çalıştırıyor.
Peki yazdığınız komut, bu dizinlerin içinde de yoksa başımıza ne gelir? Klasik bir hata: "command not found"
ali@ubuntu24:~$ which gnuadmin
ali@ubuntu24:~$ type gnuadmin
-bash: type: gnuadmin: not found
ali@ubuntu24:~$ gnuadmin
gnuadmin: command not found
ali@ubuntu24:~$
"gnuadmin" gibi bir ifadeyi which programı ile sorguladık. Yanıt alamadık. type ile sorguladık ve Bash'in bu komuttan ne anladığını sorduk. Komutu bulamadığını ifade etti. Son olarak gnuadmin yazarak bunu çalıştırmayı denedik ve başarısız olduk. Çünkü ne internal olarak böyle bir komut var ne de $PATH değişkeninde yer alan dizinlerde.
Peki Bash, her zaman gidip bu path'lerde iglili komutu arar mı? Hayır. Bulduktan sonra, bunu bir "hash tablosunda" tutar. Neyin nerede olduğunu zaten bir kere bulmuştur. Belirli bir süreliğine (veya oturumunuz boyunca) bu bilgiyi bir tabloda tutar ve siz aynı komutları yazdıkça, tekrar tekrar bunu aramaz. Aşağıdaki örneği inceleyin:
ali@ubuntu24:~$ type cp
cp is /usr/bin/cp
ali@ubuntu24:~$ type mv
mv is /usr/bin/mv
ali@ubuntu24:~$ cp
cp: missing file operand
Try 'cp --help' for more information.
ali@ubuntu24:~$ type cp
cp is hashed (/usr/bin/cp)
ali@ubuntu24:~$ mv
mv: missing file operand
Try 'mv --help' for more information.
ali@ubuntu24:~$ type mv
mv is hashed (/usr/bin/mv)
type cp ve type mv ile bu komutlar hakkında bilgi istedik. İkisi için de, bunların "/usr/bin" dizininde yer alan programlar olduğu bilgisini aldık. Sonra sadece cp yazıp Enter'a bastık. Tabii bu komut bu şekilde kullanılmaz. Hata verdi. Fakat hatayı veren kim? cp programının kendisi. Benzer şekilde mv programı da hata verdi. Fakat önemli olan nokta şu. Bu programlar "çalıştırıldı". Çalıştırıldı ve hata verdiler. Önemi yok. Neticede, Bash bu programların yerini buldu ve onları çalıştırdı. Bu nedenle tekrar type ile sorgu yaptığımızda, bu programlar için "mv is hashed (/usr/bin/mv)" gibi bir ifade görüyoruz.
Hatanın Kaynağı
İleride karşılaşacağınız hataları daha iyi yorumlamak için, bu hataların nereden geldiğini iyi anlamanız çok önemli. Hatayı veren Bash mi? Yoksa programın kendisi mi? Yukarıdaki örneklerde hatayı veren, cp ve `mv programları. "Şuradan yardım alabilirsin", "Şunu deneyebilirsin", "Bunu unuttun mu?" gibi mesajlar; aslında bu programları geliştiren kişilerin yazdığı mesajlar. Gösterilen hataların ve ipuçlarının, Bash ile hiçbir ilgisi yok.