Linux dosya sistemi ve dizinler

Veriler, bilgisayar ortamında saklanırken dosya ve dizin adı verilen ögeler içinde muhafaza ve organize edilirler. Dosya ve dizinler de daha büyük kapsayıcılar olan dosya sistemleri üzerinde bulunurlar. Aşağıda bir dosya sisteminin sahip olduğu bu hiyerarşinin bir gösterimi yer alıyor.

Dosyalar genel olarak; aynı türden verileri bir arada tutmak, gerektiğinde erişmek veya değiştirmek için kullanılan ögelerdir. Dizinlerin kendisi ise bir veri saklamak için kullanılmaz; bunun yerine dosyaları türlerine göre bir arada tutmak, yani organize etmek için kullanılırlar. Bir dizin kendi içerisinde, başka dizinleri ve dosyaları bulundurabilir; fakat dosyalar kendi içerisinde başka dosyalar ya da dizinler bulunduramaz. Ayrıca, bir dizin içinde aynı isme sahip sadece bir dosya olabilir.

Dosyalar barındırdıkları veri türlerine göre çeşitli kategorilere ayrılabilir; sistem dosyaları, yapılandırma (ayar) dosyaları, resim ve görüntü dosyaları, çalıştırılabilir dosyalar vb. Bu örnekler daha da artırılabilir. Linux işletim sistemi, standart olarak on binlerce dosya ve dizinden oluşur. İlk defa 1993 yılında standartları oluşturulmaya başlanan Linux dizin hiyerarşisine göre bir Linux işletim sisteminin dizinleri aşağıdaki gibi oluşturulmuştur.

[email protected]:/ $ ls /
bin   dev  home  lost+found  mnt  proc  run   srv  tmp  var
boot  etc  lib   media       opt  root  sbin  sys  usr

Bu dizinler kullanılan dağıtımın türüne göre ufak farklılıklara sahip olabilir; fakat kitap boyunca referans alınan Raspberry Pi OS işletim sisteminin (popüler Linux işletim sistemi dağıtımı Debian’dan türetilmiştir) kök dizininde yer alan dizinler tam olarak yukarıdaki gibidir. Linux işletim sistemlerinde kök dizin (root directory), “/” sembolü ile gösterilir ve dosya sisteminde bulunan tüm dizinlere ev sahipliği yapar. Windows kullanıcıları açısından bu dizini “c:\” dizini ile ilişkilendirmek anlaşılır olmasını sağlayabilir. Kitap boyunca hem bu dizinler ile çalışacağımızdan hem de gerektiğinde doğru dizinin hangisi olduğuna karar verebilmek için, her bir dizinin kullanım amacını (standardında belirtilen) bilmek faydalı olacaktır. Dizinlerin kullanım amaçları kısaca şöyle sıralanabilir:

  • / : kök dizindir ve diğer tüm dizinler ve dosyalar bu dizin altında bulunur
  • /bin: (binary) Sistemin çalışması ve yönetilmesi için gerekli çalıştırılabilir dosyalar bulunur.
  • /dev: (devices) Donanım bileşenlerini yönetmek ve erişmek için gerekli aygıt dosyalarını bulundurur. Linux’ta tüm donanım bileşenlerinde /dev altında bulunan aygıt dosyaları aracılığı ile işlem yapılır ve erişilir.
  • /home: Ev dizini. Sistemde hesabı bulunan kullanıcıların kişisel dizinleri bu dizin altında oluşturulur. Windows’taki “Documents and Settings” ve “Applications” dizinlerine benzer bir amacı yerine getirir.
  • /lost+found: Dosya sistemi tamiri sırasında ortaya çıkartılan bir dosya adına sahip olmayan dosyalar bu dizinde biriktirilir.
  • /mnt: (mount) USB flaş bellek ya da harddisk gibi haricen bağlanan dosya sistemleri bu dizin altına bağlanarak erişilebilir olur.
  • /proc: (process) Sistemde çalışan tüm süreçlere (programlar) ait bilgiler bu dizinde saklanır. Bu dizin RAM üzerinde oluşturulan sanal bir dosya sistemin bağlandığı bir dizindir.
  • /run: Açılış sırasında (ön yükleme) kullanılan systemd servislerinin çalışma zamanı bilgileri burada tutulur.
  • /srv: (serve) ftp, rsync ve www gibi hizmetlere özel verileri tutar.
  • /tmp: (temporary) Geçici dosya saklama dizinidir. Programların geçici dosyaları saklamak için kullandığı dizindir, genellikle her açılış sırasında temizlenir.
  • /var: (variables) Günlük dosyaları, yazıcı yazdırma kuyruğu verileri ve e-posta gelen kutusu gibi değişken veriler bu dizinde tutulur.
  • /boot: Linux işletim sisteminin açılış sırasında ön yükleme yapabilmesi için gerekli dosyalar bu dizinde tutulur.
  • /etc: (et cetera: vesaire) Linux’un ver üzerinden çalışan servis ve programların ayar ve yapılandırma dosyaları bu dizinde tutulur.
  • /lib: (library) Çekirdek modülleri ve paylaşılan program kütüphanelerinin bulunduğu dizindir.
  • /media: SD Kart ve USB flaş bellek gibi çıkartılabilir dosya sistemlerinin bağlandığı dizindir.
  • /opt: (optional) İşletim sistemi ve çekirdeği için zaruri olmayan seçimlik programların kurulduğu dizindir.
  • /root: Linux işletim sisteminin yönetici kullanıcısı olan root’un ev dizinidir. Bu dizinin erişim izinleri sadece root kullanıcısına açıktır.
  • /sbin: (system binaries) Sistemin önyüklemek için (boot) kullanılan ve genellikle sistem yöneticisi (root) haklarıyla çalışan programların bulunduğu dizindir.
  • /sys: Linux çekirdeğinin parametrelerine ulaşmak için bir dosya sistemi arabirimi olarak görev yapar. Çekirdek parametrelerinin güncel değerlerine bu dizin aracılığı ile ulaşılır.
  • /usr: İşletim sistemi ile gelen veya paket yöneticisi aracılığı ile sisteme kurulan programlar bu dizinde barındırılır.

Özel aygıt dosyaları ^

/dev dizini içinde Linux’un mimarisine has bazı özel dosyalar bulunur. Kitabın ilerleyen bölümlerinde kullanılan bu dosyalar hakkında bahsetmek de fayda vardır.

/dev/null ^

/dev/null her türlü veriyi girdi olarak kabul eden ve yok eden bir işleve sahiptir. Bir komutun ya da programın ürettiği herhangi bir ekran çıktısı ekran tamponuna yazılarak terminal ekranında görüntülenmesi sağlanır. Ekran çıktısına yansıyan her şey bellekte bir miktar yer işgal eder. Ekran çıktısına ihtiyaç olmayan durumlarda çıktı /dev/null aygıtına yazılarak yok edilmesi sağlanabilir. Bu Linux’ta çok sık başvurulan bir yöntemdir.

/dev/zero ^

/dev/zero, görev olarak /dev/null ile yanı şeyi yapar; fakat okuduğu her byte için null üreten bir çıkış akışına (stream) sahiptir.

/dev/random ^

/dev/random, her okunduğunda rastgele bir sayı üretir. Bu üretim Linux çekirdeğinin güvenli rastgele sayı üreteci tarafından yazılımsal yolla yapılır.

Komut kabuğu ^

Raspberry Pi OS dağıtımı çekirdek olarak Linux’u kullanır. Linux çekirdeği ise programlar ile sistem donanımları arasındaki koordinasyonu sağlayarak donanım bileşenlerinin verimli ve güvenli şekilde çalıştırılmalarını sağlar. Yani, Linux, kullanıcıların programlara ve sistem kaynaklarına erişmesi için doğrudan bir yol sunmaz, bu iş kabuk adı verilen aracı programlar ile gerçekleştirilir. Kullanıcılar ise, ister fiziksel bir klavye ve ekran kullanarak isterse de uzak ağ bağlantısı yoluyla bir terminal bağlantısı açarak bu kabuğa/komut satırına erişir. Bu ilişki aşağıdaki şekilde gösterilmiştir.

Komut kabuğu ve işletim sistemi arasındaki ilişki

Birçok bilgisayar kullanıcısı komut satırı ile ilk defa Linux’ta tanışırlar. Kabuk Linux’un en önemli parçasıdır. Aslında tüm işletim sistemlerinin bir komut arayüzü bulunur. Örneğin bir Windows bilgisayarının komut satırına Windows+R tuş bileşimine basıp, cmd yazarak ulaşabilirsiniz. MacOS’da ise Command+Space tuş bileşimine bastıktan sonra terminal yazarak erişebilirsiniz. Telefonunuzda, tabletinizde, modeminizde ve televizyonunuzda komut satırı arabirimi bir yerlerde gizlidir. Cihazıyla ilgili standart dışı bir iş yapmak isteyen birisi için komut satırı çoğu zaman sınırsız bir erişim sağlar. Linux’ta durum farklıdır; çünkü komut satırı arabirimi diğerlerine göre sıklıkla kullanılır, tamamen gizlenmemiştir.

Raspberry Pi OS’un ve diğer meşhur birçok Linux dağıtımının varsayılan kabuğu bash’dir. bash (Bourne Again SHell,) Bourne Shell adı verilen daha eski bir kabuk programından türetilmiştir. bash dışında tcsh, ksh, zsh ve fish gibi birçok kabuk programı vardır; ancak bash daha yaygındır.

Örneğin, kitap boyunca da kullanılan bash isimli kabuk bize aşağıdaki gibi bir komut satırı/arabirimi sunar. Bizler bu komut arabirimi sayesinde işletim sistemine komutlar gönderir ve çıktılarını alırız. Aslında kabuk da bir programdır ve çoğu zaman komut diye tabir ettiğimiz diğer programları (ls, cp, mv, sudo, vb.) çalıştırarak bize çıktılarını döndürür.

[email protected]:~ $

bash kullanıcının komut girişine hazır olarak beklediğini ifade etmek için komut satırının sonuna $ işaretini (prompt işareti) basar. Bu işaretin öncesinde ise kullanıcının içinde bulunduğu aktif dizin yazılıdır. Tilda (~) sembolü kullanıcının kendi ev dizininde bulunduğu anlamına gelir. Bu işaretin de önünde @ (at) sembolü ile ayrılmış olarak oturum açmış kullanıcının adı ve oturum açılmış olan bilgisayarın adı (hostname) yazar. Aşağıdaki görselde tüm bu bahsedilen kısımları görüyorsunuz.

Bash komut satırının yapısı

bash kabuğu çalışırken, işlerinizi kolaylaştırabilecek ve komut yazımınızı hızlandırabilecek birkaç pratik özelliğe sahiptir:

  • Komut konsolunda komut yazarken tab tuşuna bastığınız takdirde komutun kabuk tarafından otomatik olarak tamamlandığını görebilirsiniz. Yalnızca komutun kabuk tarafından tahmin edilebilmesi için yeterli sayıda başlangıç harfini girmeniz gerekir. Ayrıca dizin ve dosyaları parametre olarak alan komutlar da tab tuşu ile otomatik tamamlatılabilir. Kullanmanızı şiddetle tavsiye ederim.
  • Yanlış yazdığınız bir komutu silmek için backspace tuşu yerine Ctrl+U bileşimini kullanarak imlecin solunda kalan tüm ifadelerin silinmesini sağlayabilirsiniz.
  • Bash komut kabuğu en son yazılan komutları hafızasında tutar, bu komutlara yukarı ve aşağı ok tuşlarını kullanarak erişebilirsiniz. Ayrıca history komutunu vererek de listelenmesini sağlayabilirsiniz.
  • Konsola çıktı basan bir program, komut satırını kullanmanızı doğal olarak engeller. Programı sonlandırmak için Ctrl+C, durdurmak (suspend) Ctrl+Z tuş bileşimlerini kullanabilirsiniz. Programı durdurmak ya da kapatmak yerine sadece konsol çıktısını durdurmak isterseniz Ctrl+S tuş bileşimini kullanabilirsiniz. Ctrl+S ile durdurulan çıktının devam etmesini sağlamak için Ctrl+Q tuş bileşimini kullanabilirsiniz.
  • Ctrl+D tuş bileşimi ise kabuğa EOF karakterini (End of File) göndererek çıkmasını sağlar. exit komutu ile aynı işleve sahiptir, yani bash kabuk oturumu sonlandırılır.
  • Ctrl+L konsol ekranını temizler. clear komutu ile aynı işleve sahiptir.
  • Ctrl+_ kullanıcının konsola yazdığı karakter işlemlerini geri alır.
  • Örneğin en son yazdığınız belli bir komutu seçenekleri ile birlikte tekrar çalıştırmak isterseniz başına ! (ünlem) karakterini koyabilirsiniz. Eğer sadece komutun kendini görmek isterseniz sonuna :p yazabilirsiniz. Örneğin, en son çalıştırdığınız find komutunun ne olduğunu görmek isterseniz !find:p yazın. Bu komutu çalıştırmak için de !find yazın.

Raspberry Pi’ın arka planında hali hâlihazırda altı farklı terminal istemcisi (tty) çalışır durumdadır. Bu terminaller arasında geçiş yapmak için klavyeden Ctrl+Alt+F1 tuş bileşimini kullanabilirsiniz. F1’den F6’ya kadar var olan terminaller arasında ilgili F tuşuna basarak geçiş yapabilirsiniz. Grafik kurulumunuz mevcutsa ve aktifse Ctrl+Alt+F7’ye basarak grafik ortamına geçiş yapabilir, grafik ortamı içinde terminal penceresi açmak için ise Ctrl+Alt+t tuş bileşimini kullanabilirsiniz.

Hızlı çalışması gereken ve nispeten basit komutlar ise kabuğun içine gömülmüştür. Bunlara builtin commands adı verilir ve harici komutlar gibi /usr/bin altında çalıştırılabilir bir dosyaları (ELF) bulunmaz. Doğrudan Bash’in içinden bir alt program olarak çağrılırlar. Bash’in dâhili komutları aşağıdaki gibidir:

alias, bg, bind, break, builtin, case, cd, command, compgen, complete, continue, declare, dirs, disown, echo, enable, eval, exec,  exit,  export,  fc,  fg,  getopts, hash, help, history, if, jobs, kill, let, local, logout, popd, printf, pushd, pwd, read,  readonly,  return,  set,  shift,  shopt,  source, suspend,  test,  times,  trap,  type, typeset, ulimit, umask, unalias, unset, until, wait, while

Bash’in Dahili ve Harici Komutları

stdout ve stderr çıktılarının yönlendirilmesi ^

Linux’un (çekirdek) mimarisinde stdout, stdin, stderr adı verilen akışlar (stream) vardır. Örneğin terminal ekranına herhangi bir çıktı basan bir program, bu çıktıyı stdout (standart çıkış) adı verilen akışa yönlendirir. Stdout akışına yönlendirilen her şey varsayılan olarak terminal ekranına basılır. Diğer taraftan, ilgili program hazırlanırken bu mimari kuralına uyularak yazılmışsa, programın hata çıktıları ise stderr adlı akışa yönlendirilir. Eğer stderr akışının ürettiği çıktılar herhangi bir program tarafından okunmaz ise bu akış stdout akışına yönlendirilir. Programa girdiğimiz veriler ise stdin adlı akış üzerinden okunur. Aşağıdaki C programının kaynak kodunda bu durum örneklendirilmiştir.

[email protected]:~ $ nano std.c
#include <stdio.h>
void main()
{
  fprintf(stdout, "Merhaba Eros!\n");
  fprintf(stderr, "Merhaba Ares!\n");
}
[email protected]:~ $ gcc stDC -o std_ornek
[email protected]:~ $ ./std_ornek
Merhaba Eros!
Merhaba Ares!

Bir Linux programı başladığında standart olarak bu üç akış (stdout, stdin, stderr) da etkinleştirilir ve her bir akış terminal programı (bash) ile ilişkilendirilir. Programcı, çıktıyı doğru akışa yönlendirecek kodları kullanmışsa çıktılar ilgili akışlara yönlendirilir ve işlevsel olur. Bu kodlar kullanılmasa dâhi ilgili akışlar program açık kaldığı sürece var olmaya devam ederler. Bu derleyicinin bir özelliğidir. Programa çalıştırma esnasında verilen seçeneklerin/parametrelerin stdin üzerinden okunmadığını belirtmek isterim. stdin sadece programın çalışması esnasında kullanıcını veri girişi için kullanılabilir olur.

Yukarıdaki programın stderr akışı özel olarak bir çıktıya yönlendirilmemişse çekirdeğin tahsis ettiği stdout standart çıktı akışına yazılır. stderr akışını ayrı olarak okumak için 2>&1 işlevinden yararlanılır.

[email protected]:~ $ ./std_ornek 2>&1 > echo
Merhaba Ares!

Burada yapılan şey 2 numaralı stderr akışının 1 numaralı stdout akışına oradan da echo komutunun girdisine (stdin) yönlendirilmesidir. Benzer şekilde bir programın hata çıktılarını bir log dosyasına yönlendirmek için de aşağıdaki gibi bir kullanım gerçekleştirilebilir (Bu kullanım özellikle periyodik olarak arka planda çalıştırılan cronjob görevlerinin hatalarını geçmişe dönük kayıt altına almak için faydalıdır).

[email protected]:~ $ sudo ./std_ornek > /dev/null 2> hatalar.txt
[email protected]:~ $ cat hatalar.txt
Merhaba Ares!

Yukarıdaki örnekte 1 numaralı stdout akışı null aygıtına, 2 numaralı stderr akışı ise hatalar.txt adlı dosyaya yönlendirilmiştir. /dev/null aygıtı dipsiz bir kuyu gibidir ve gönderilen herşeyi içine alarak yok eder.

Aşağıdaki örnekte ise hem stdout hem de stderr, hatalar.txt dosyasına yönlendirilmiştir. Bu yönlendirme stderr (2)’nin stdout (1)’a yönlendirilmesi ile gerçekleştirilmiştir.

[email protected]:~ $ sudo ./std_ornek > hatalar.txt 2>&1
[email protected]:~ $ cat hatalar.txt
Merhaba Ares!
Merhaba Eros!

stdout ve strderr akışlarını ayrı ayrı yönlendirmek için aşağıdaki örnek kullanılabilir:

[email protected]:~ $ sudo ./std_ornek 1>mesajlar.txt 2>hatalar.txt
[email protected]:~ $ cat mesajlar.txt
Merhaba Gunes!
[email protected]:~ $ cat hatalar.txt
Merhaba Bulut!

Özel karakter ve işleçler ^

Tüm işletim sistemlerinin komut kabuklarında olduğu gibi Linux’ta da geçerli bazı özel karakterler ve işlevler yer alır. Aşağıda bir listesini bulabileceğiniz bu özel karakterler Linux’ta oldukça etkin kullanılır ve komut satırı işlemlerini oldukça esnek ve işlevsel bir hale getirir. Örneğin * karakteri buna bir örnektir. Yıldız karakteri bir dosya sistemi komutu ile birlikte kullanıldığında birçok karakter yerine geçer. Örneğin bir dizinde yer alan ve uzantısı tmp olan dosyaları silmek isterseniz rm *.tmp gibi bir komut çalıştırabilirsiniz. Benzer şekilde adı disk ile başlayan tmp uzantılı dosyaları silmek için ise rm disk*.tmp komutunu çalıştırabilirsiniz.

*,?Dosya/dizi adı belirtimlerinde joker karakter yerine geçer. *, tüm karakterler yerine geçerken, ? ise sadece tek bir karakter yerine geçer.
&Bir komutun sonunda kullanıldığında, komutu arka plana iter. Arka planda çalışan komutun çıktısı standart çıktıya basılmaya devam edilirken kullanıcı yeni bir komut çalıştırabilir.
;Birden fazla komut çalıştırmak gerektiğinde, komutları ayırmak için kullanılır. Örn: clear; ls-la
$Dolar karakterinin birçok kullanım alanı vardır. Bir kabuk değişkeni tanımlamak için değişken adının soluna koyulur. Bir komut çalıştırıp çıktısını bir değişkende saklamak için parantez işaretleri ile birlikte, bir aritmetik işlemi gerçekleştirmek içinde ise çift parantezli işlemin solunda kullanılır. Örn: ev_dizini=$(pwd) yas=$((1938-1881))
>Bir komutun çıktısını bir dosyaya girdi olarak aktarmak için kullanılır. Dosya mevcut değilse oluşturulur. Mevcutsa içeriği silinerek üzerine yazılır. Örn: echo $((1938-1881)) > ataturk.txt ls > dosya_listesi.txt
>>Bir komutun çıktısını bir dosyaya girdi olarak aktarmak için kullanılır. Dosya mevcut değilse oluşturulur. Mevcut ise çıktı dosyanın sonuna eklenir.
|Pipe ya da boru karakteri, bir komutun çıktısını (STDOUT), ardından gelen bir başka komuta girdi (STDIN) olarak aktarmak için kullanılır. Örn: echo “Selam! Birsel.” | grep -o “Selam”
\Ardından gelen karakterin özel karakter olarak yorumlanmasını önler. Örneğin bir ekran çıktısında ; sembolü kullanılmak istenirse \; şeklinde yazılabilir.
~Tilda adlı bu sembol mevcut kullanıcının ev dizinini ifade eder. Tek başına kullanıldığında geçerli kullanıcının ev dizini döndürürken, kendinden sonra bir kullanıcı adı belirtildiğinde kullanıcının ev dizinini döndürür. Örn: cd ~okoca
!!Kabuk ortamında son çalıştırılan komutu çalıştırır.
Diğer karakterlerDiğer karakterlerin geniş bir listesini tiny.cc/bash_chars web adresinden görebilirsiniz.

bash komut kabuğu ile betik yazmak ^

Bash komut kabuğu betik (script) adı verilen toplu iş dosyalarını da destekler. Toplu iş dosyaları ile tıpkı bir programlama dilinde olduğu gibi birden fazla komut belli bir düzende çalıştırılabilir, değişken, şartlı ifade ve döngüler kullanılarak karmaşık görevler için otomasyonlar gerçekleştirilebilir. Bash çok sayıda özelliğe sahiptir. Öyle ki, bunlar bir kitabın konusu dâhi olabilir. Bu başlıkta tatbikî sadece küçük bir tanıtım yapmakla yetineceğiz. Aşağıda, nano editörü ile basit bir metin belgesi olarak yazılan (betik.sh) bir bash betiği görülmektedir:

[email protected]:~ $ nano betik.sh
#!/bin/sh
echo "Adın ne?"
read isim
echo "Nasılsın, $isim?"
read durum
echo "Ben de $durum, tesekkurler!"

Betiğin içinde kullanılan bazı anahtar kelimelere bakacak olursak; öncelikle, dosyanın başındaki #! İle başlayan satır bu betiğin /bin/sh disk konumunda kayıtlı bash yorumlayıcısı (kabuğun kendisi) tarafından çalıştırılacağını ifade eder. Betik metni bu programa gönderilir ve çalıştırılması sağlanır. Eğer, ! sembolü unutulup sadece # sembolü yazılırsa, o satır yorum satırı halini alır ve kabuk tarafından çalıştırılmaz. # sembolü betik içine açıklayıcı metinler yerleştirmek için kullanılan bir işarettir. Ardından gelen echo komutu (ya da programı) kendisine seçenek olarak verilen metinsel ifadeyi terminal ekranına yazacaktır. Metinsel ifadeler ise çift tırnak işaretleri arasında belirtilir. read isim ile devam eden satır, klavyeden enter tuşuna basılıncaya kadar yazılanları alarak isim değişkeni içerisine kaydeder. Dördüncü satırdaki echo ifadesine dikkat edecek olursanız isim değişkeninin başına $ işareti koyulmuştur. Bu işaret, isim değişkeninin içinde saklanan değerin yazılmasını sağlar. Dolar ($) işaretini kaldırarak değişikliği gözlemleyebilirsiniz.

Bu betiğin kabuk tarafından çalıştırılabilmesi için çalıştırma izninin (x) verilmesi gerekir. Bunun için chmod aracını aşağıdaki gibi çalıştırdıktan sonra betik adının önüne ./ yazarak betiğimizi başlatalım.

[email protected]:~ $ chmod +x betik.sh
[email protected]:~ $ ./betik.sh
Adın ne?
Yakup
Nasılsın, Yakup?
orta sekerim
Ben de orta sekerim, tesekkurler!

Betik çalıştıktan sonraki ekran görüntüsü yukarıdaki gibi olmuştur.

Bash kabuk ortamı oldukça gelişkin betik yetenek ve işlevlerine sahiptir. Bu yeteneklerin düzenli bir listesini devhints.io/bash web adresinde bulabilirsiniz.

Yazar: Özgür Koca

Yazar - Tankado.com

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

This site uses Akismet to reduce spam. Learn how your comment data is processed.