# Döküman Hakkında

Linux Yönetimi kitabı VeriTeknik ekibinin vermiş olduğu Linux, Ağ ve Güvenlik eğitimlerinde yardımcı bir kaynak olması amacıyla hazırlanmıştır, kitap bir çok konu hakkında derinlemesine bilgi içermekle birlikte, anlatılan konuların kolay ve sürdürülebilir metodları da izah edilmiştir, örneğin Apache ve PHP kısmında sürümlerin derlemesinden bahsedilirken, kitabın sonunda repolar kullanılarak uygulanan hızlı ve güvenilir çözümlere de yer verilmiştir. Bize göre iyi bir Linux uzmanı pratikliğin yanı sıra konulara derinlemesine hakim olmalıdır. Burada paylaştığımız bilgiler veri merkezimizde karşımıza çıkan bir çok problemin de pratik cevaplarını içermektedir.

İnternet'in kullanımının yoğunlaşması sonucunda açık kaynak kodlu, defalarca sınanmış ve hem kararlılığı hem de güvenliği konusunda ticari yazılımlara alternatif olmaya başlayan GNU/Linux işletim sistemleri, gelecekte de çok yaygın bir şekilde kullanılacaktır. Özellikle Sanayi 4.0 ile birlikte, İnternete bağlanan cihaz sayısı logaritmik olarak yükselmektedir ve bu sistemlerin birçoğunda gömülü sstem olarak Linux türevleri kullanılmaktadır. Ülkemizin Sanayi 4.0 treninde yerini alabilmesi temelde yatan işletim sistemini iyi bilmesi ile daha da kolay olacaktır, biz de toplumsal kalkınmanın paylaşımdan geçeceğine inanıyoruz.

**Kitap çoğunlukla Web Hosting ve Uygulama Hosting açısından sürümleri ele almıştır. Gömülü sistemlerin anlatıldığı bölümlerde ise daha çok I/O kullanım bilgilerine değinilecektir.** Kitabın amacı okuyucuya Hosting ortamının/web servislerinin kurulmasında ve işletilmesinde gerekli olacak bilgiyi vermektir.

Veri merkezimizde edindiğimiz bilgiler güncellendikçe, biz de kitapta değişiklikler yapmaktayız, eğer kitabın basılı sürümü elinizdeyse, en son sürüme ve örnek kodlara [https://linux-yonetimi.veriteknik.net.tr/](https://linux-yonetimi.veriteknik.net.tr) adresinde de ücretsiz olarak ulaşabilirsiniz.

Döküman veya GNU/Linux hakkında herhangi sorunuz için bize <iletisim@veriteknik.com>\
adresinden ulaşabilirsiniz.

Discord kanalımız: <https://discord.gg/YEx4DhNyMj>

## Yazarlar Hakkında

### Cem Karaca

Üniversite yıllarında, İnternet'in gelişimi ile birlikte Sunucular, Ağ ve Linux ile tanışmıştır, LYNX Browser ile siyah ekranda başlayan serüveni, 2004 yılından bu yana Ankara'da Veri Merkezi işleterek devam etmektedir. Elektrik & Elektronik Yüksek Mühendisi olan yazarın 2003 yılında yayınlanmış "Pedagojik Destekli uzaktan talepli Video Sistemi (VoD)" yüksek lisans tezidir. IEEE indeksli makaleleri bulunan yazar, multimedia transferi için kullanılabilen RUDP protokolünü tasarlamıştır. Uzmanlık Alanları: MCF, C/C++, Gömülü Sistemler, Ağ ve Sürücü Programlama.

### Mustafa Emre Aydın

Lisans eğitimi sırasında çok miktardaki bilimsel verinin tasniflenmesi ve anlamlandırılması üzerine çalışırken GNU/Linux sistemler üzerinde MPI ve Embarrasingly Parallel algoritmalar geliştirerek programlama ve sistem yönetimi deneyimi kazanmıştır. Temel bilimler ve sistem programcılığında Python'un yaygınlaşmasıyla "Wavelet Dönüşümüne Dayalı Dinamik Güç Spektrumu Eldesi" konulu yüksek lisans tez çalışmasının yanı sıra pek çok görüntü işleme ve güvenlik sistemini de bu dilde geliştirmiştir. Gömülü Linux sistemlerin yanı sıra sunucu ve ağ programlama yapan yazar, Doktora çalışmasına X-Işın Uydu Gözlemlerinin Hassas Zaman Ölçümü konusunda devam etmektedir.

## VeriTeknik

VeriTeknik, ağ iletişimi ve altyapısı üzerine uzmanlaşmış mühendislik çözümleri sunmaktadır. Veri merkezleri, dağıtık sunucu sistemleri, ağ güvenliği ve ağ yazılımları üzerinde özgün çalışmalar yapmaktadır. 2004 yılından bu yana kazanmış olduğumuz deneyimi sektördeki diğer meslektaşlarımızla ve siz değerli okuyucularımızla paylaşmak, ülkemizin açık kaynak kodlu sistemlerde bir nebze de olsa gelişme sağlamasını görmekten mutluluk duyarız. VeriTeknik, Ankara ve Amsterdam ofislerinde faaliyet göstermektedir, toplamda 10 ülkede veri merkezleri ile çalışmaktadır. Tübitak Pardus Çözüm ortağı olan VeriTeknik aynı zamanda Ultra Electronics ve Realsec'in Türkiye, Hollanda, Doğu Avrupa ve Türki Cumhuriyetler resmi distribütörüdür.

## Teşekkürler

Katkılarından dolayı değerli iş arkadaşlarımız Tunç Yıldırım, Yaşar Celep ve Ömrüm Çetin'e, bu kitabın oluşmasına vesile olan Hazine Müsteşarlığı'na ve Nuri Akman'a teşekkür ederiz.

## Notlar

### Komut Gösterimi

Dökümanda komutlar tek başına gösterildiklerinde başında $ veya # gibi işaretler olmadan kullanılmıştır. Örneğin:

```bash
which vi
```

Öte yandan, çıktısı belirtilecek komutlarda, girdinin ayırt edilebilmesi için, prompt'un tamamı gösterilmiştir. Örneğin:

```bash
eaydin@dixon ~ $ which vi
/usr/bin/vi
```

Çıktısı çok uzun olan ve yeni girdi kullanılan komutlarda, girdiler ve çıktılar ayrı komut blokları halinde gösterilmiştir.

### Çevrimdışı Okumak

Dökümanın PDF halinde yatay eksende çok uzun olan komutlar veya çıktıları tam olarak görülmemektedir. Bu durumun önüne geçmek için uzun komutlar **\\** işareti ile alt satırdan devam etmiştir.

HTML okunduğunda bu problem bulunmamaktadır, HTML scroll-bar (kaydırma çubuğu) sunmaktadır.

Kitabı çevrimdışı HTML olarak okumak isterseniz, `wget` ile edinebilirsiniz.

```bash
wget -m -p --convert-links -P kitap https://veriteknik.gitbooks.io/linux-yonetimi/content/
```

Yukarıdaki komut, bulunduğunuz dizine `kitap` isminde bir dizin oluşturur ve kitabı indirir. Komutun açıklamasını [Gelişmiş Terminal Komutları](https://veriteknik.gitbooks.io/linux-yonetimi/content/gelismis_terminal/gelismis_terminal_komutlari.html) bölümündeki [wget](https://veriteknik.gitbooks.io/linux-yonetimi/content/gelismis_terminal/wget.html) kısmında öğrenebilirsiniz.

### Terimler

Terimler Türkçe karşılıkları belirtilerek çoğunlukla İngilizce olarak kullanılmıştır. Okuyucuların teknik terimleri ve karşılaştıkları problemleri İngilizce kullanarak Google'lamaları tavsiye edilmektedir.

**Cem Karaca** & **M. Emre Aydın**

... Veri her yerde ...

Copyright 2015-2025 VeriTeknik Bilişim, Basın ve Yayın Ltd. Şti. İzinsiz alıntı yapılamaz, kopyalanamaz ve çoğaltılamaz.


# Linux ve GNU'nun Geçmişi

## Unix ve C

1970'lerde, AT\&T'nin Bell Laboratuarlarında Ken Thompson ve Dennis Ritchie öncülüğünde geliştirilmiştir. Her ne kadar işletim sistemi Bell ve AT\&T'de kullanılmak üzere tasarlanmışsa da, 1970'lerin sonunda AT\&T lisansı başka firmalara da açmıştır, böylece çeşitli firma ve kurumlar kendi Unix türevlerini piyasaya sürmüştür: Kaliforniya Üniversitesi, Berkeley (BSD), Microsoft (Xenix), IBM (AIX), Sun Microsystems (Solaris).

![](/files/-L9H1_N2oj91NCvMVpS2)

*Ken Thompson (solda) ve Dennis Ritchie (sağda)*

1990'ların başında AT\&T Unix'in haklarını Novell'e satmıştır, Novell de 1995'te Santa Cruz Operations'a (SCO) satmıştır. Ancak günümüzde UNIX (büyük harflerle yazıldığında) endüstri standardı konsorsiyumu (The Open Group) tarafından tescillenmiştir ve ticari bir isim olarak kullanılmaktan ziyade, bir işletim sistemleri ailesi olarak anılmaktadır.

Unix'i diğer işletim sistemlerinden ayıran noktalardan birisi, işletim sisteminin hemen her platformda çalışabiliyor olmasıdır. Bu sayede Unix çok rahat bir biçimde farklı işletim sistemlerine dönüştürülebilmiş, farklı işlemci/bellek mimarilerinde yer edinebilmiştir.

Ayrıca **Unix felsefesi** olarak adlandırılan yapısı sistemi rahat geliştirilen, tutarlı bir hale getirmiştir. Bu felfese ile işletim sistemi küçük, basit, az ancak iyi tanımlanmış işler yapan programlardan oluşur. Bu programlar ortak bir dosya sistemi aracılığıyla iletişim kurarlar ve işletim sistemi programlanabilir bir kabuk (shell) ile basit işlemler yapan programları bir araya getirerek karmaşık problemlerin çözümüne olanak sağlar.

C programlama dili, Dennis Ritchi tarafından Unix işletim sistemi için geliştirilmiştir. Unix işletim sisteminin büyük çoğunluğu C ile yazılmıştır. C programlama dili, hem pek çok donanım üzerinde çalışabildiğinden, hem de öncülleri BCPL veya B gibi tip kullanmayan (typeless) bir dil olmadığından, ideal bir *sistem programlama dili* olarak nitelendirilir.

![](/files/-L9H1_NxSrbD8iyh5dJN)

C programlama dilinin yaygınlaşmasına yardımcı olması dışında, bilgisayar bilimlerine yaptığı katkılardan ötürü Brian Kernighan ve Dennis Ritchie'nin yazdığı *The C Programming Language* kitabının yayımlanması da bir dönüm noktası kabul edilir.

## GNU

Bir yandan Ken Thompson ve Dennis Ritchie C ve Unix'i geliştirirken, Richard Stallman 1971 yılında MIT Yapay Zeka Laboratuvarlarında çalışmaya başlamıştı. Burada çalıştığı yıllarda, özellikle bir Xerox Lazer Yazıcı'nın sürücüsünün kaynak kodunun paylaşılmaması, ve beraberinde etrafında çalışan programcıların kendi geliştirdiği kodları Gizlilik Sözleşmeleri (Non-Disclosure Agreement) dahilinde satmaya başlamasıyla yazılımın özgür olması gerektiğini savunmaya başladı. Aslında o yıllarda programların kaynak kodlarıyla birlikte dağıtılıyor olması yaygındı ancak bu durum ticari kaygılarla ve firmalar arası rekabetle ortadan kalkmaya başlayınca, Richard Stallman bunun aksini savunmak için gerekli argümanlarını yeterince gözden geçirmediğini, inşa etmemiş olduğunu fark etti.

![](/files/-L9H1_OMz3wrVhD8mwpP)

*Richard Stallman*

1980'lerden hemen her yazılım "değiştirilmeye ve kullanıcıları tarafından geliştirilmeye" yasak halde dağıtılıyordu. Bunun üzerine Richard Stallman Unix benzeri bir işletim sistemi ve bu sistemi çalıştıran yazılımlar grubu geliştirmeye karar verdi. Geliştirdiği bu yazılımları dağıtırken de daha önce karşılaştığı durumla başkalarının karşılaşmasını engellemek için özel bir lisanslama biçimi geliştirdi, lisanslama isminin adı GPL (General Public License) idi. Geliştirmeye başladığı sisteme ise "GNU is Not Unix"in kısaltması olarak GNU ismini verdi. Bu yazılımlar grubunu dağıtırken Özgür Yazılım Derneğ'ni (FSF: Free Software Foundation) kurmuş ve işinin MIT veya Yapay Zeka Laboratuvarları ile ilişkilendirilmemesi için MIT'den istifa etmiştir.

GNU'nun geliştirilmesi, Unix felsefesi dahilinde olmuştur. İşletim sistemi Unix-benzeri bir sistem olacak, baştan yazılacak ancak Unix'in bazı eksiklikleri giderilecekti. İşletim sisteminin çekirdeğine **Hurd**, çevre yazılımlarına ise GNU Projesi dahilindeki yazılımlar olarak bakılıyordu. Çoğunlukla sistemin geliştirilmesine çevre yazılımlarla başlanılmıştır. Bunların başında C derleyicisi olan GNU C Compiler (gcc) gelir.

## Linux

1980'ler boyunca GNU'nun gelişmesiyle birlikte, 1991 yılında Finlandiya'lı bilgisayar bilimleri öğrencisi olan Linus Torvalds kendi işletim sistemi çekirdeğini yazmıştır. Bu çekirdeği tamamen hobi olarak geliştirmiştir ve duyurusunu Usenet üzerinden duyururken "GNU kadar gelişmiş ve profesyonel bir şey olmayacağını" da belirtmiştir. İlk geliştirdiği dağıtımda, sadece çekirdeği yazdığı için, çevre araçları (küçük programlar, derleyiciler ve kabuk) GNU Projesinden almıştır.

![](/files/-L9H1_OjJprPxLnMExmG)

*Linus Torvalds*

Linus Torvalds'in geliştirdiği işletim sistemini ilk başta farklı bir lisansla dağıtmış olsa da, 1992'de GNU GPL ile dağıtmıştır ve sistem bundan sonra başka programcılar tarafından hızla geliştirilmeye başlanmıştır. 1993 yılında 100'den fazla programcı Linux çekirdeğini geliştirmekle uğraşmıştır. Çekirdeğin geliştirilmesi haricinde Linux'un GNU ortamı ile uyumlu çalışması sağlanılmış ve aynı yıl içerisinde Slackware, yılın ilerleyen aylarındaysa Debian dağıtımları piyasaya çıkmıştır. Bugün hala geliştirilen bu iki dağıtımtan Slackware en eski dağıtım olup, Debian ise en yaygın dağıtımlardan birisidir.

Bugün GNU Hurd'ün geliştirilmesi hale devam etmektedir ancak Linux çekirdeği kadar yaygın bir kullanımı yoktur. Bugün piyasadaki yaygın sistemler, Linux çekirdeği etrafına GNU yazılımlarıyla dağıtılarak gelmektedir, dolayısıyla bu sistemlere **GNU/Linux** sistemler denilmektedir, ancak kolay söylenmesi amacıyla sistemin tamamına "Linux" denilmesi yaygındır. Richard Stallman 1995-1996 yıllarında bunun önüne geçilmesi için *LiGNUx* gibi bir terim önermiştir ancak bu söylem de tutmamıştır.


# CentOS, Debian ve FreeBSD Ana Sürümlerin Farkları

Linux ve BSD dünyasında birçok farklı dağıtım bulunmaktadır. Her birinin kendine özgü felsefesi, geliştirme modeli ve hedef kitlesi vardır. Sunucu ortamları için en yaygın kullanılanları genellikle Red Hat Enterprise Linux (RHEL) tabanlı dağıtımlar, Debian tabanlı dağıtımlar ve FreeBSD'dir.

Bu bölümde, bu ana grupların temel farklılıklarına ve özelliklerine odaklanacağız. Unutulmamalıdır ki, "en iyi" dağıtım diye bir kavram yoktur; en uygun dağıtım, projenin gereksinimlerine, sistem yöneticisinin deneyimine ve kişisel tercihlere bağlı olarak değişir.

## Red Hat Enterprise Linux (RHEL) ve Türevleri (CentOS Stream, Rocky Linux, AlmaLinux)

* **Köken:** Ticari bir ürün olan Red Hat Enterprise Linux'u temel alırlar. RHEL, kurumsal düzeyde destek ve uzun vadeli kararlılık sunar.
* **CentOS Projesi:** Eskiden RHEL'in birebir kopyası olan CentOS Linux, popüler bir ücretsiz alternatifti. Ancak proje, RHEL'in bir sonraki sürümüne giden geliştirme dalı olan **CentOS Stream**'e odaklanmıştır. CentOS Stream, daha hızlı güncellemeler sunar ancak RHEL kadar uzun vadeli kararlılığa sahip olmayabilir.
* **RHEL Klonları (Rocky Linux, AlmaLinux):** CentOS Linux'un yerini doldurmak amacıyla topluluk tarafından geliştirilen dağıtımlardır. RHEL ile tam uyumluluk ve benzer bir kararlılık sunmayı hedeflerler.
* **Paket Yönetimi:** RPM paket formatını ve `yum` / `dnf` paket yöneticilerini kullanırlar.
* **Release Modeli:** Genellikle belirli aralıklarla çıkan ana sürümlere (point releases) sahiptirler (CentOS Stream daha çok rolling release'e yakındır). Uzun destek süreleri (LTS) sunarlar.
* **SELinux:** Güvenlik odaklı bir yapıya sahiptirler ve SELinux (Security-Enhanced Linux) genellikle varsayılan olarak etkindir.
* **Hedef Kitle:** Kurumsal ortamlar, sunucular, kararlılık ve uzun vadeli destek arayan kullanıcılar.

## Debian ve Türevleri (Ubuntu)

* **Köken:** Tamamen topluluk tarafından yönetilen, köklü ve etkili bir projedir. Özgür yazılım ilkelerine sıkı sıkıya bağlıdır ("Debian Sosyal Sözleşmesi").
* **Ubuntu:** Debian'ı temel alan, Canonical firması tarafından desteklenen popüler bir dağıtımdır. Hem masaüstü hem de sunucu ortamlarında yaygın olarak kullanılır. Debian'a göre daha sık sürüm çıkarır ve bazen daha güncel paketler içerir.
* **Paket Yönetimi:** DEB paket formatını ve `apt` (Advanced Package Tool) paket yöneticisini kullanırlar. Geniş bir yazılım deposuna sahiptirler.
* **Release Modeli:** Debian'ın üç ana dalı vardır: `stable` (kararlı, eski ama güvenilir paketler), `testing` (bir sonraki kararlı sürüm için hazırlık) ve `unstable` (en güncel paketler, geliştirme dalı). Ubuntu'nun ise belirli aralıklarla çıkan sürümleri ve uzun destekli (LTS) sürümleri bulunur.
* **Felsefe:** Özgür yazılım, topluluk yönetimi ve evrensel işletim sistemi olma hedefleri ön plandadır.
* **Hedef Kitle:** Sunucular, masaüstü kullanıcıları, geliştiriciler, geniş paket deposu ve esneklik arayanlar.

## FreeBSD

* **Köken:** Berkeley Software Distribution (BSD) Unix'ten türemiştir. Linux'tan farklı bir çekirdek ve temel sistem araçları kullanır.
* **Geliştirme Modeli:** İşletim sistemi çekirdeği ve temel kullanıcı alanı araçları (userland) tek bir ekip tarafından birlikte geliştirilir. Bu, daha entegre ve tutarlı bir sistem sağlar. Linux dağıtımlarında ise çekirdek ayrı, kullanıcı alanı araçları farklı projeler tarafından geliştirilir ve dağıtım tarafından bir araya getirilir.
* **Paket Yönetimi:** İki ana yöntem vardır:
  * **Ports Collection:** Kaynak koddan derleme yaparak yazılım kurmayı sağlayan bir sistemdir. Yüksek düzeyde özelleştirme imkanı sunar.
  * **pkg:** Önceden derlenmiş ikili (binary) paketleri kurmayı sağlayan modern paket yöneticisidir.
* **Release Modeli:** Belirli aralıklarla çıkan kararlı sürümleri (RELEASE) ve geliştirme dalları (STABLE, CURRENT) bulunur. Güvenlik ve kararlılığa büyük önem verilir.
* **Özellikler:** Güçlü ağ yığını (network stack), ZFS dosya sistemi desteği, Jails (hafif sanallaştırma/konteyner benzeri yapı) gibi özellikleriyle bilinir.
* **Lisans:** Linux'un kullandığı GPL yerine daha esnek olan BSD lisansını kullanır.
* **Hedef Kitle:** Ağ cihazları, sunucular, yüksek performans ve kararlılık gerektiren sistemler, Unix felsefesine yakınlık duyanlar.

## Sonuç

Hangi dağıtım ailesinin veya FreeBSD'nin seçileceği, tamamen ihtiyaçlara ve önceliklere bağlıdır.

* **Kurumsal destek, RHEL uyumluluğu ve uzun vadeli kararlılık** öncelikliyse RHEL veya klonları (Rocky/AlmaLinux) iyi bir seçenek olabilir. Geliştirme sürecine daha yakın olmak isteyenler CentOS Stream'i tercih edebilir.
* **Geniş paket deposu, güçlü topluluk desteği ve esneklik** aranıyorsa Debian veya Ubuntu uygun olabilir. Ubuntu, masaüstü kullanımı ve daha güncel paketler için popülerdir.
* **Maksimum kararlılık, performans (özellikle ağ konusunda), ZFS gibi gelişmiş özellikler ve entegre sistem yapısı** önemliyse FreeBSD güçlü bir alternatiftir.

Doug Gwyn'in Unix felsefesi üzerine söylediği şu söz, bu sistemlerin genel yaklaşımını özetler niteliktedir:

*"Unix was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things."*

Bu sistemler, kullanıcıya büyük bir güç ve esneklik sunar, ancak bu gücün sorumlulukla kullanılması gerektiğini varsayar.


# Temel Komutlar

Bu bölümde temel terminal kullanımının yanı sıra, Linux dizin yapısının özellikleri, kullanıcı ve grup yetkilendirmeleri, dosyaların çalıştırma modları ve dosyaları düzenlemek için temel metin düzenleyiciler incelenecektir.

* [Temel Terinal Komutları](/temel-komutlar/temel-terminal-komutlari)
* [Yardım Dosyaları](/temel-komutlar/yardim-dosyalari)
* [Dosya İzinleri, Yetkiler, Kullanıcılar ve Gruplar](/temel-komutlar/dosya-izinleri-yetkiler-kullanicilar-ve-gruplar)
* [Dosya Düzenleme Araçları](/temel-komutlar/dosya-duezenleme-araclari)
* [Sıkıştırılmış Dosyalar](/temel-komutlar/sikistirilmis-dosyalar)


# Temel Terminal Komutları

GNU/Linux üzerinde temel olarak sınıflandırabileceğimiz komutlar şu şekilde sıralanabilir.

| Komut | Açıklama                                             | Örnek                               |
| ----- | ---------------------------------------------------- | ----------------------------------- |
| cd    | Dizin değiştirme                                     | cd /var/www                         |
| ls    | Dizin içeriği listeleme                              | ls /var/www                         |
| mkdir | Dizin oluşturma                                      | mkdir /var/www/html                 |
| rmdir | Dizin silme                                          | rmdir /var/www/html                 |
| pwd   | Mevcut dizini gösterme                               | pwd                                 |
| rm    | Dosya silme                                          | rm /var/www/html/index.html         |
| cp    | Dosya kopyalama                                      | cp /etc/hosts /root/hosts.bak       |
| mv    | Dosya taşıma                                         | mv /root/hosts.bak /root/hosts.bak2 |
| cat   | Dosya içeriği görüntüleme                            | cat /etc/hosts                      |
| echo  | Standart çıktıya yazdırma                            | echo "test"                         |
| du    | Dizin/dosya boyutu gösterme                          | du -sh .                            |
| touch | Boş dosya oluşturma / Erişim zamanını güncelleme     | touch yeni\_dosya.txt               |
| head  | Dosyanın başlangıcını gösterme (varsayılan 10 satır) | head /var/log/syslog                |
| tail  | Dosyanın sonunu gösterme (varsayılan 10 satır)       | tail /var/log/syslog                |
| less  | Dosya içeriğini sayfa sayfa gösterme                 | less /etc/passwd                    |

Yukarıda sıralanan komutlar, GNU/Linux komut satırının çok küçük bir kısmını oluştursa da, en sık kullanılan komutlar arasında yer aldıklarını söyleyebiliriz. Burada altının çizilmesi gereken önemli bir nokta, GNU/Linux komutlarının birbirleriyle uyum içinde çalışabilecek biçimde tasarlanmış olmalarıdır ve bunu yapmak için standart girdi/çıktı yönlendirmeleri haricinde, pek çok parametre alabilmektedirler. Programların parametreleri ve programların genel özellikleri hakkında bilgi almak için man komutu kullanılabilir. Örneğin du komutu hakkında bilgi almak için

```bash
man du
```

yazmak yeterli olacaktır. Bu durumda terminalde du komutunun manual dosyaları görülür. Bu dosyalar artık standartlaştığı için, internetten de bulunabilir. Örneğin `du` için manual dosyasına şu adresten erişebilirsiniz: <http://man7.org/linux/man-pages/man1/du.1.html>

Bir diğer önemli nokta, GNU/Linux dizin yapısının anlaşılmasındadır. GNU/Linux'ta dizin gösteriminin birkaç yolu vardır. Örneğin pek çoğumuzun aşina olduğu, "bir üst dizine çıkma" işlemi aşağıdaki şekilde yapılır.

```bash
cd ..
```

Bu komutu uygularken aslında yaptığımız işlem ".. isimli dizine gir" demek oluyor. GNU/Linux dizin yapısında her zaman ".." isimli dizin, mevcut dizinin bir üst dizinine işaret ettiği için üst dizine çıkmış oluruz. Dolayısıyla eğer iki üst dizine çıkmak isteseydik

```bash
cd ../..
```

komutu yeterli olacaktı. Benzer şekilde tek nokta ile ifade edilen dizin "." her zaman mevcut dizindir. Dolayısıyla mevcut dizin ile ilgili bir işlem yapmak istiyorsak, "." koymamız yeterli olacaktır.

Örneğin hosts dosyamızı mevcut dizine kopyalamak istiyorsak aşağıdaki komutu uygulamamız gerekir.

```bash
cp /etc/hosts .
```

Çoğunlukla GNU/Linux dizin yapısına yeni başlayan kişilerin karıştırdığı nokta, göreli dizinlerdir. Yukarıdaki örnekte `/etc/hosts` şeklinde dizin ifade ettik. Eğer bunu başındaki `/` olmadan yazsaydık, yani `etc/hosts` şeklinde yazsaydık, mevcut dizinin altında bir `etc` klasörü, onun da altında bir `hosts` dosyası arayacaktı sistem. Dolayısıyla mevcut dizinimize göre (yani göreli) bir gösterim kullanmış olacaktık.


# Yardım Dosyaları

Geleneksel UNIX sistemlerde yardım dosyaları **man** komutu kullanılarak erişilen "manual" dosyalarıdır. Bu dosyalar sistemin tamamı için yazılmış ve bir hiyerarşi içerisindedir. man dosyaları **troff** yapısını kullanırlar, bu yapı sayesinde dosyaların çıktı alınca da rahat okunacak şekilde yazılması sağlanmıştır. GNU Projesi dahilinde **man**ual'ların hiyerarşisi çağdışı bulunmuş, ayrıca troff yapısının çıktı kaygısının yersiz olduğu düşünülmüştür. Bu yüzden alternatifi olarak **info** komutu ve yapısı oluşturulmuştur. Kullandığınız programa ve sisteme göre edineceğiniz dökümantasyon farklı olacaktır ancak bugün hemen her komutun **man** ve **info** sayfası mevcuttur. Eski olmasına rağmen **man** kullanımı, sistem yöneticilerinin alışkanlıkları arasındadır.

![](https://imgs.xkcd.com/comics/manual_override.png)

*Kaynak:* <https://xkcd.com/912/>

Her ne kadar **man** sayfaları UNIX'in bütün araçları için geliştirilmiş olsa da, her programcı gibi Ken Thompson ve Dennis Ritchie de dökümantasyon yazmaktan pek hoşlanmazlardı. UNIX'in ilk iki yılı boyunca hiç dökümantasyonu olmamıştır. En sonunda Thompson ve Ritchie yöneticileri Doug McIlroy'un ısrarları sonucu ilk **man** dosyalarını 1971'de yazmıştır.

Ayrıca, birçok GNU komutu, temel kullanım bilgilerini ve parametrelerini hızlıca görmek için `--help` seçeneğini destekler (örneğin, `ls --help`). Bu, genellikle `man` veya `info` sayfalarına göre daha kısa ve özet bir bilgi sunar.

## man Bölümleri

man sayfaları çeşitli bölümlerden oluşur. Bunun temel nedeni, aynı isimde birden fazla sayfa olabilmesidir. Örneğin **mkdir** için iki sayfa mevcuttur, birisi shell komutu olanı için, diğeri de System call olanı içindir. Bu yüzden iki farklı bölümde iki farklı mkdir man sayfası bulunur. Birisi birinci bölümde bulunur ve **mkdir(1)** şeklinde gösterilir, diğeriyse ikinci bölümde bulunur ve **mkdir(2)** şeklinde gösterilir.

man sayfaları aşağıdaki gibi bölümlendirilmiştir:

1. Programlar veya shell komutları - rm(1)
2. Unix ve C Sistem çağrıları - ioctl(2)
3. C Programlar için kütüphane çağrıları - printf(3)
4. Özel Dosyalar - null(4)
5. Dosya Biçimleri - ext4(5)
6. Oyunlar - fortune(6)
7. Diğerleri - regex(7)
8. Bakım - 1. bölümde yer alan programların bakımları ile ilgili

Herhangi bir komutun **man** sayfasına erişmek için, man komutuna kendisini parametre olarak göndermek yeterlidir.

```bash
man mkdir
```

Yukarıdaki örnekte man komutu, mkdir'in 1. bölümdeki sayfasını getirecektir, çünkü en düşük bu seviyede dosyası bulunur. Örneğin **null** için bu komut 4. bölümdeki sayfayı getirir, çünkü 1. 2. ve 3. bölümlerde sayfası yok.

Oysa `mkdir` komutunun 2. bölümdeki sayfasına erişmek isteseydik, yazmamız gereken komut şöyle olurdu:

```bash
man 2 mkdir
```

## apropos ve whatis

Herhangi bir konu hakkında yardım sayfalarını taramak isterseniz, `apropos` komutunu kullanabilirsiniz. `man -k` ile aynı işi yapmaktadır, dolayısıyla aşağıdaki komutlar size aynı çıktıyı verecektir:

```bash
man -k malloc
apropos malloc
__after_morecore_hook (3) - malloc debugging variables
__free_hook (3)      - malloc debugging variables
__malloc_hook (3)    - malloc debugging variables
__malloc_initialize_hook (3) - malloc debugging variables
__memalign_hook (3)  - malloc debugging variables
__realloc_hook (3)   - malloc debugging variables
malloc (3)           - allocate and free dynamic memory
malloc_get_state (3) - record and restore state of malloc implementation
malloc_hook (3)      - malloc debugging variables
malloc_info (3)      - export malloc state to a stream
malloc_set_state (3) - record and restore state of malloc implementation
malloc_stats (3)     - print memory allocation statistics
malloc_trim (3)      - release free memory from the top of the heap
malloc_usable_size (3) - obtain size of block of memory allocated from heap
mtrace (1)           - Interpret output from MALLOC_TRACE
mtrace (3)           - malloc tracing
muntrace (3)         - malloc tracing
```

## info Kullanımı

GNU projesinin `man` sayfalarına alternatifi olan `info` sistemi, belgeleri "node" adı verilen hiyerarşik bir yapıda sunar. `info` sayfalarında gezinmek için genellikle şu tuşlar kullanılır:

* `n`: Sonraki node'a gitmek.
* `p`: Önceki node'a gitmek.
* `u`: Bir üst node'a gitmek.
* `Enter`: İmlecin üzerindeki bağlantıyı (genellikle `*` ile başlar) takip etmek.
* `q`: `info`'dan çıkmak.
* `h`: Yardım ekranını görmek.

Örneğin, `ls` komutu için `info` sayfasını açmak isterseniz `info ls` komutunu kullanabilirsiniz.

**whatis** komutu ise bir komut hakkında size kısa bilgi vermeyi amaçlamaktadır.

```bash
whatis malloc
malloc (3)           - allocate and free dynamic memory
```

## man Dosyalarının Yolu

Her ne kadar Dosya Sistemi Hiyerarşi Standardında man dosyalarının yolu için `/usr/share/man` belirlenmişse de, her zaman buna uyulmaz, ve sistem birden fazla noktayı tarar.

Sisteminizde man dosyalarının nerelerde olduğunu öğrenmek için `manpath` komutunu veya `$MANPATH` çevre değişkenini kontrol edebilirsiniz. Ancak `manpath` komutu her zaman kurulu olmayabilir.

```bash
# manpath komutu varsa:
manpath
/usr/local/man:/usr/local/share/man:/usr/share/man

# Alternatif olarak çevre değişkeni:
echo $MANPATH
```

Yukarıdaki örnekte **:** ile ayrılmış değerler, farklı dizinlere işaret eder. Belirli bir komutun man sayfasının tam yolunu bulmanın daha güvenilir bir yolu `man -w` veya `man --where` komutunu kullanmaktır:

```bash
man -w mkdir
/usr/share/man/man1/mkdir.1.gz
```

Eğer komutun birden fazla bölümde man sayfası varsa, `man -wa` veya `man --where --all` komutu tüm yolları listeler:

```bash
man -wa mkdir
/usr/share/man/man1/mkdir.1.gz
/usr/share/man/man2/mkdir.2.gz
```


# Dosya İzinleri, Yetkiler, Kullanıcılar ve Gruplar

Linux ve türevi işletim sistemlerinin en önemli özelliklerinden birisi, "her şey bir dosyadır" felsefesidir. Bütün Linux komutlarının ve sistemlerinin çalışma prensibi bu felsefeye göre oluşturulmuştur, böylece klavye, ses cihazları, monitör gibi cihazlar bile bir metin dosyası gibi müdahale edilebilir. Örneğin cat komutu ile istenilen veri ses kayıt cihazına işaret eden "dosyaya" yönlendirilebilir.

Her şeyin bir dosya olması, beraberinde bu dosyalara erişim yetkilerini de getirmiştir. Linux üzerinde dosyalarınızın yetkilerini görüntülemek için ls komutunu -l parametresiyle çalıştırabilirsiniz.

```bash
eaydin@eaydin ~/devel/crc $ ls -l
total 4
-rwxr-xr-- 1 eaydin plugdev 1925 Nov  4 01:36 crc8.py
```

Yukarıdaki örnekte, \~/devel/crc dizininin içindeki dosyalar yetki ve izinleriyle birlikte listeleniyor. Linux üzerinde "\~" karakteri özel bir dizin işaretçisidir. Bu işaret ile mevcut kullanıcının "home" dizini kastedilir. Örneğin *eaydin* kullanıcısı için \~ dizini her zaman /home/eaydin dizinine işaret eder, oysa *root* kullanıcısı için "/root" dizinine işaret eder.

Bu örnekte dizinimizde tek dosya olduğunu görüyoruz, evet sadece bu dosyanın özelliklerine bakmak isteseydik, parametre olarak dosyanın ismini verebilirdik.

ls komutu çıktısının üçüncü ve dördüncü sütunlarında bu dosyanın hangi kullanıcı ve hangi gruba ait olduğu görülüyor. *crc8.py* dosyası *eaydin* kullanıcısına ve *plugdev* grubuna aitmiş.

ls komutu çıktısının ilk sütunu ise bu kullanıcı ve grubun hangi yetkilere sahip olduğunu belirtiyor.

```bash
-rwxr-xr--
```

Buradaki ilk karakter ("-") şimdilik bir kenara bırakırsak, diğer karakterler 3'erli olarak sırasıyla dosya sahibinin, grubunun ve diğer kullanıcıların yetkilerini göstermektedir. Kısacası *rwx* yazan kısım *eaydin* kullanıcısının yetkilerini, *r-x* yazan kısım *plugdev* grubunun yetkilerini, *r--* yazan kısım için sistemde geriye kalan bütün kullanıcıların yetkilerini göstermektedir.

Bu yetkiler çeşitli anlamların kısaltmalarıdır. *r* harfi okuma yetkisi (read), *w* yazma yetkisi (write) ve *x* çalıştırma yetkisi (execute) anlamına gelmektedir. Bu durumda sistemimizdeki crc8.py dosyasını herkes okuyabiliyor, dosya içeriğini sadece *eaydin* kullanıcısı değiştirebiliyor, dosyayı *eaydin* kullanıcısı ve *plugdev* grubuna dahil bütün kullanıcılar çalıştırabiliyor demektir.

*rwx* yetkilendirme kullanımını `chmod` komutuyla yapabiliriz. `chmod` komutu hem sembolik (harflerle) hem de oktal (rakamlarla) gösterimi destekler.

**Sembolik Gösterim:**

* **Kimi etkileyecek:** `u` (user/sahip), `g` (group/grup), `o` (others/diğerleri), `a` (all/tümü - varsayılan).
* **Ne yapılacak:** `+` (izin ekle), `-` (izin çıkar), `=` (izinleri tam olarak ayarla).
* **Hangi izin:** `r` (okuma), `w` (yazma), `x` (çalıştırma).

Örnekler:

```bash
# Herkese (a) yazma (+) izni ekle
chmod a+w crc8.py 
# veya kısaca (a varsayılan olduğu için):
chmod +w crc8.py

# Grup (g) ve diğerlerinden (o) çalıştırma (x) iznini kaldır (-)
chmod go-x crc8.py

# Sahip (u) için okuma ve yazma (rw), grup (g) için sadece okuma (r), diğerleri (o) için hiçbir izin verme (=)
chmod u=rw,g=r,o= crc8.py 
```

**Oktal (Rakamlarla) Gösterim:**

Öte yandan, *rwx* yetkilendirme biçiminin farklı bir notasyonu bulunmaktadır. Okuma, yazma ve çalıştırma işlemlerinin her biri farklı bir rakamla ifade edilmek üzere, toplamları bir dosya için tüm yetkileri gösterebilir.

Örnekle açıklamak gerekirse, okuma işlemi için 4 sayısı, yazma işlemi için 2 sayısı ve çalıştırma işlemi için 1 sayısı tahsis edilmiştir. Bu durumda Dosyanın hem okunması, hem yazılması hem de çalıştırılması için 7 sayısı (4+2+1=7) yetkilendirmeyi ifade edebilir. Veya sadece okuma ve çalıştırma yetkisi vermek için 5 sayısı (4+1=5) yeterli olacaktır.

Bu durumda crc8.py dosyamızın **rwxr-xr--** yetkisini rakamla ifade etmek istersek, 754 sayısı yeterli olacaktır. İlk rakam olan 7 dosya sahibi eaydin kullanıcısının **rwx** yetkisine, ikinci rakam olan 5 dosyayla ilişkilendirilen plugdev grubunun **r-x** yetkisine, 4 sayısı ise sistemde geri kalan tüm kullanıcıların **r--** yetkisine işaret etmektedir.

**chmod** ile bu yetkilendirmeyi vermek için aşağıdaki komutu uygulayabiliriz.

```bash
chmod 754 crc8.py
```

## Dizin Yetkilendirmesi

Dizin yetkilendirmeleri, dosya yetkilendirmelerinden farklı anlamlar taşır.

| Yetki      | Rakamsal Gösterim | Anlamı                                                                                                                                        |
| ---------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| Okuma      | 4                 | Kullanıcının, dizinin içini görüntüleyebileceği anlamına gelir. Örneğin ls komutu ile içeriği görüntülenebilir                                |
| Yazma      | 2                 | Kullanıcının, dizinin içinde yeni dosya oluşturabileceği veya mevcut dosyaları silebileceği anlamına gelir. (Aşağıdaki önemli notu inceleyin) |
| Çalıştırma | 1                 | Kullanıcının ilgili dizine girebileceği (cd) anlamına gelir.                                                                                  |

## Garip Yetkilendirme Durumları

Bazı dosyaların yetkileri pek alışıldık durumda olmayabilir. Dosyanızı bu şekilde tutmanızın pek bir anlamı yoktur.

* **100 veya 300:** Dosyanın 1 veya 3 yetkisinin olması (yani *--x* veya *-wx* yetkisinin olması) hiçbir anlam ifade etmeyecektir. Çünkü bu dosyanın kişi tarafından çalıştırılabileceği ancak okunamayacağı anlamına gelir. Linux üzerinde bir dosya okunamazsa, çalıştırılamaz da.
* **200:** Bu durum bir dosyaya yazabileceğiniz, ancak okuyamayacağınız anlamına gelir. Belki kullanıcının okumasını istemediğiniz, ancak yazmasını istediğiniz log/rapor dosyaları için kullanılabilir, ancak pek rastlanan bir durum değildir.
* **007:** Bu dosya sahibi ve grubu tarafından hiçbir şekilde erişilemezken geri kalan tüm kullanıcılar tarafından erişilebilir. Potansiyel güvenlik açığıdır ve durumun incelenmesi gerekir.
* **000:** Dosyaya kimsenin bir şey yapamayacağı anlamına gelir. Sadece root kullanıcısı dosyayı okuyabilir veya yazabilir. Öte yandan dosyanın sahibi dosyanın izinlerini değiştirebilir. Dolayısıyla bazı programlar dosyanın geçici süre koruma altında olması için bu durumu seçebilir.

|   |   | Önemli NOT                                                                                                                                                                                                                                                                                                                              |   |
| - | - | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - |
|   |   | Bir dosyaya yazma yetkinizin olmaması, onu silemeyeceğiniz anlamına gelmez. Dizin yetkileri dosya yetkilerinden farklıdır ve bir dizine yazma yetkinizin olması, o dizin içindeki dosyaları silebileceğiniz anlamına gelmektedir. Kısacası dosyanın izinleri **000** olsa bile, dizinde yazma yetkiniz varsa, o dosyayı silebilirsiniz. |   |
|   |   |                                                                                                                                                                                                                                                                                                                                         |   |

## Diğer Dosya Yetkileri

Dosya izinlerini incelerken, *ls -l* komut çıktısının ilk sütunundaki ilk karakteri şimdilik gözardı etmiştik. Bu karakter dosya hakkındaki bazı özel durumları göstermektedir. Aşağıdaki değerleri alabilir:

| Gösterim | Açıklaması                                                                                                                                                                                                          |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| -        | Normal dosya.                                                                                                                                                                                                       |
| l        | Sembolik link. Dosyanın bir link olduğu, işaret ettiği dosyanın farklı noktada olduğunu belirtir.                                                                                                                   |
| b        | Dosyanın bir blok dosyası olduğu anlamına gelir. Kısacası bu dosyaya yazarken (ve okurken) bloklar halinde yazılmalıdır. Genellikle /dev altındaki sabit disk dosyalarında görülür.                                 |
| c        | Dosyanın bir karakter özel dosyası olduğu anlamına gelir. Yani blok dosyalarına benzerdir ancak yazıp okuma işlemlerinde karakter kullanılmalıdır. Örneğin /dev altındaki seri port cihazları bu özelliğe sahiptir. |
| s        | Soket dosyası. Programların birbirleri ile iletişim kurarken, doğrudan dosya işaretçisi aracılığıyla veri iletmelerini sağlar.                                                                                      |

Öte yandan **setuid** ve **setgid** bitleri, dosyanın çalıştırma izninin yerine geçebilir (`x` yerine `s` veya `S` olarak görünür).

* **setuid (SUID):** Bir çalıştırılabilir dosyada setuid biti ayarlandığında, dosyayı çalıştıran kişi, dosyayı çalıştırırken geçici olarak dosyanın *sahibinin* yetkilerine sahip olur. Örneğin, `passwd` komutu normal kullanıcıların kendi şifrelerini değiştirebilmesi için setuid root olarak ayarlanmıştır. Dikkatli kullanılmazsa ciddi güvenlik açıklarına neden olabilir.
* **setgid (SGID):** Bir çalıştırılabilir dosyada setgid biti ayarlandığında, dosyayı çalıştıran kişi, dosyayı çalıştırırken geçici olarak dosyanın *grubunun* yetkilerine sahip olur.
* **setgid (Dizinlerde):** Bir dizine setgid biti (`chmod g+s dizin_adi`) ayarlandığında, o dizin içinde oluşturulan yeni dosyalar ve alt dizinler, otomatik olarak o dizinin grubuna sahip olur (oluşturan kullanıcının birincil grubu yerine). Bu, bir grup projesi için paylaşılan dizinlerde çok kullanışlıdır. Dizinlerde setuid bitinin ise standart bir etkisi yoktur ve genellikle kullanılmaz.

*crc8.py* dosyamızın setuid (sahip için) ve setgid (grup için) olması durumunda *ls -l* çıktısı aşağıdaki gibi olurdu:

```bash
-rwsr-sr-- 1 eaydin plugdev 1925 Nov  4 01:36 crc8.py 
```

Eğer setuid veya setgid biti ayarlanmışsa ancak ilgili konumda çalıştırma (`x`) izni yoksa, `s` yerine büyük `S` harfi görünür. Bu genellikle anlamsız bir durumu veya bir hatayı belirtir. Örneğin:

```bash
-rwSr-Sr-- 1 eaydin plugdev 1925 Nov  4 01:36 crc8.py 
```

Yukarıdaki örnekte, hem sahip hem de grup için setuid/setgid bitleri ayarlanmış ancak çalıştırma izni verilmemiştir.

Bir başka özel yetki biçimi **sticky bit**'tir (`t` veya `T`). Genellikle `/tmp` gibi herkesin yazabildiği dizinlerde kullanılır. Bir dizinde sticky bit ayarlıysa (`chmod +t dizin_adi`), o dizin içindeki bir dosyayı veya alt dizini yalnızca dosyanın/dizinin sahibi, dizinin sahibi veya root kullanıcısı silebilir ya da yeniden adlandırabilir. Yetki dizisinin son karakterinde (`x` yerine) `t` veya `T` olarak görünür (`T` yine çalıştırma izni olmayan durumu belirtir).

```bash
drwxrwxrwt 1 eaydin plugdev    144 Nov  7 16:00 crc
```

## Kullanıcı ve Grup Düzenleme

Linux üzerinde bir kullanıcı eklemek son derece kolaydır. **root** yetkisine sahip olduğunuzda aşağıdaki komutu çalıştırırsanız **eaydin** isimli bir kullanıcı oluşturulacaktır.

```bash
useradd veriteknik
```

**eaydin** kullanıcısını şifresini tanımlamak için aşağıdaki komut çalıştırılmalı, ardından iki kere şifre girilmelidir.

```bash
passwd eaydin
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully
```

Şimdi sistemimizde bir **veriteknik** grubu tanımlayacağız, ardından **eaydin** kullanıcısını bu gruba ekleyeceğiz.

```bash
groupadd veriteknik
usermod -a -G veriteknik eaydin
```

Yukarıdaki tekniklerle kullanıcı ve grup ayrı ayrı oluşturulur. Örneğin aşağıdaki komut, mevcut gruba yeni bir kullanıcı oluşturup ekler.

```bash
useradd -G veriteknik ckaraca
```

Sistemden kullanıcı ve grup silmek içinse aşağıdaki komutlar uygulanabilir.

```bash
userdel ckaraca
groupdel veriteknik
```

Bir kullanıcının hangi gruplarda yer aldığını görüntülemek için **id** komutu kullanılabilir.

```bash
id eaydin
uid=1001(eaydin) gid=1002(eaydin) groups=1002(eaydin),1001(veriteknik)
```

Benzer şekilde **groups** komutu da kullanılabilir.

```bash
groups eaydin
eaydin : eaydin adm cdrom sudo dip plugdev lpadmin sambashare veriteknik
```

Gördüğünüz gibi **eaydin** kullanıcısı hem **eaydin** grubunda, hem de **veriteknik** grubunda yer almaktadır. Her kullanıcının kendi grubu da bulunur ve bu gruplar silinemez, bu gruplara *primary group* denilir.

```bash
groupdel eaydin
groupdel: cannot remove the primary group of user 'eaydin'
```

Bir kullanıcıyı belirli bir ikincil gruptan silmek için genellikle `gpasswd` komutu kullanılır (bu komut çoğu dağıtımda bulunur):

```bash
# eaydin kullanıcısını veriteknik grubundan sil
gpasswd -d eaydin veriteknik 
```

Debian/Ubuntu tabanlı sistemlerde `deluser` komutu da bu iş için kullanılabilir:

```bash
# Debian/Ubuntu'da alternatif:
# deluser eaydin veriteknik
# Removing user `eaydin' from group `veriteknik' ...
# Done.
```

Bir kullanıcıyı, *primary group* haricindeki tüm gruplardan (yani tüm \_secondary group\_lardan) silmek içinse aşağıdaki komut uygulanabilir.

```bash
usermod -G "" eaydin
```

Sistemdeki bütün gruplar, /etc/group dosyasında yer alır, aşağıdaki komut ile tamamı listelenebilir. Komutun çalışma prensibi **Gelişmiş Terminal Komutları** bölümünde incelenecektir.

```bash
cut -d: -f1 /etc/group
```

Benzer şekilde sistemdeki tüm kullanıcıları aşağıdaki gibi görüntüleyebilirsiniz.

```bash
cut -d: -f1 /etc/passwd
```

Bu bilgiler doğrudan `/etc/group` (gruplar için) ve `/etc/passwd` (kullanıcılar için) dosyalarında saklanır. Ancak bu dosyaları doğrudan düzenlemek yerine kullanıcı/grup yönetimi komutlarını (useradd, usermod, userdel, groupadd, groupmod, groupdel, gpasswd vb.) kullanmak genellikle daha güvenli ve tutarlıdır. `getent passwd` ve `getent group` komutları da bu dosyaların içeriğini (ve potansiyel olarak diğer veritabanlarını, örneğin LDAP) sorgulamak için kullanılabilir.


# Dosya Düzenleme Araçları

Linux üzerinde pek çok dosya düzenleme aracı bulunmaktadır. İncelemek için bu araçlardan en yaygın ve basit olanı "nano" (ve pico) ile en yaygın ve kompleks olanı "vi improved" inceleyeceğiz.

Terminal tabanlı çalışan bu progrmalar pek çok sunucuda yüklü olarak gelir veya kolaylıkla yüklenebilir. Masaüstü ortamlar kullanıldığında tabii ki kullanılabilecek metin editörlerinin sayısı çokça artacağından, bu dökümanın kapsamı dışına çıkmaktadır.

Her programcı ve her sistem yöneticisinin favori metin editörü farklıdır. Hangisinin "daha iyi" olduğu konusu metin editörlerin tarihi kadar eskidir ve hangisinin "daha iyi" olduğu konusu tamamen kişilerin tecrübeleriyle ilintili olacaktır.

![](http://imgs.xkcd.com/comics/real_programmers.png)

*Kaynak:* <http://xkcd.com/378/>


# nano ve pico

nano ve pico programları aslında birbirlerinin aynısıdır. Pico (Pine composer) geliştirildiğinde bir *free software license* altında dağıtılmadığından, kodun değiştirilerek dağıtılması yasal değildi. Dolayısıyla GNU Projesi kapsamında pico'nun işlemlerini taklit eden bir program geliştirildi ve ismi **nano** oldu. Bugün **nano** orijinal pico'dan daha kapsamlı duruma gelmiştir. Kullandığınız Linux dağıtımlarında pico komutu da aslında nano'yu çalıştırmaktadır.

Aslında pico için özgür lisanslı bir yazılım amacıyla Chris Allegretta tarafından nano ile geliştirildiğinde ismi TIP konuldu *(This isn't Pico)*, ancak Unix üzerindeki *tip* yazılımı ile karışabileceği gerekçesiyle ismi daha sonra *nano* olarak değiştirildi. *nano* SI birim sisteminde *pico*dan 1000 kat daha büyük olan bir uzunluk birimidir.

nano ve pico farklarının yaratacağı kafa karışıklığını giderdiysek, programın genel kullanımına bakabiliriz.

Önceki bölümde crc8.py dosyamızın yetkilerini görüntülemiştik.

Eğer aşağıdaki örnekleri gerçek crc8.py dosyasıyla kullanmak istiyorsanız **wget** ile dosyayı edinebilirsiniz.

```bash
wget http://bit.ly/1kBiBAE -O crc8.py
```

Yukarıdaki komut, *github* üzerinde ilgili *gist*'i indirip mevcut dizinin *crc8.py* dosyasına yazacaktır.

Şimdi dosyanın içeriğine göz atalım. Dosyaya GNU/Linux üzerinde cat, less, more, head gibi komutlarla göz atabiliriz. Ancak dosyanın içeriğini değiştirmek için bu yöntemler pratik olmayacaktır. Dosyanın bulunduğu dizinde aşağıdaki komutlardan birini çalıştırarak dosyayı nano ile açabiliriz.

```bash
nano crc8.py
pico crc8.py
```

![](/files/-L9H1SfCCKu45Czi2fiq)

Burada dosyamızın içeriğini görüyoruz. Kullandığımız dağıtımda nano dosyanın uzantısına bakarak dosyamızın içeriğinin bir Python kodu olduğunu anlıyor ve gerekli renklendirmeyi yapıyor.

Alt iki satırda gördüğünüz komutlar, klavye kısayollarıyla erişiliyor. Komutlara erişmek için CTRL ile birlikte ilgili kısayolu kullanmak gerekiyor. Örneğin "Get Help" fonksiyonunu çağırmak için CTRL+g tuşlarına basmak gerekiyor. Gelen menüden nano için kullanılabilecek bütün komutları görebilirsiniz.

![](/files/-L9H1SfKk6FHxTV7iYrv)

nano içerisinde gezinmek için ok tuşlarını kullanmanız yeterli. Değiştirmek/eklemek/silmek istediğiniz noktaya imleci getirdiğinizde istediğiniz değişikliği yaptıktan sonra dosyayı kaydetmek için CTRL+o programdan çıkmak içinse CTRL+x tuşlarını kullanmanız yeterlidir.

Dosyamızın en başında # işaretleriyle başlayan bir dizi satır görülüyor. Bu satırlar açıklama satırlarıdır, yani Python yorumlayıcısı tarafından bu satırlar gözardı edilecektir. Çoğu programlama dilinde ve çoğu ayar dosyasında açıklama satırları # işareti ile başlar.

nano, açıklama satırlarını istersek hizalı hale getirebilir. Bunun için *Justify* ve *Unjustify* komutları kullanılabilir.

İmleci açıklama satırlarının olduğu bölgeye getirip CTRL+j ile satırları hizalayabiliriz.

![](/files/-L9H1Sfj3puB9amAiGBM)

Ekranda *Can now UnJustify!* yazısı belirdi. Değişikliği gördükten sonra CTRL+u ile tekrar eski haline getirebiliriz.


# vi

vi, terminalde çok satırlı düzenleme yapabilen metin editörlerinin atalarından birisi olarak görülür. 2009'da yapılan bir anket Linux üzerine kullanılan en yaygın metin editörünün %36 ile vi olduğunu göstermektedir. Kompleks işlemleri destekleyen ve hemen her sistemde önyüklü olarak gelen vi haricinde bir diğer popüler metin editörü ise emacs'tir.

## Tarihçe

vi editörü aslında oldukça eskiye dayanan bir takım editörlerin evrilmesiyle ortaya çıkmıştır. Editörün çıkış noktası *ed* isimli editördür. *ed* Ken Thompson tarafından UNIX işletim sisteminin üç temel yapı taşından biri olarak geliştirilmiştir: assembler, editör ve shell.

*ed*'in kullanımı zamanla pek "pratik" bulunmadığından, "ölümsüzler" (immortals) tarafından kullanılabileceği espirisiyle, "ölümlüler" (mortals) için *em* geliştirildi: *editor for mortals*. *em*'nin görece yaygınlaşmasının ardından Bill Joy ve Chuck Haley kodu kendilerince şekillendirip *en* isimli bir versiyonunu geliştirdiler. Daha sonra Bill Joy tek başına *en*'yi "extend" edip *ex*'i piyasaya sürdü. *ex*'e eklenen tam-ekran görsel modu, metin editörlerinin dönüm noktası oldu. Her ne kadar bu fikir piyasadaki başka yazılımlardan alınmış olsa da, en yaygın kullanıma ulaşanı kendisi olmuştu. Zamanla *ex*'in görsel modu *(visual mode)* o kadar çok kullanıldı ki, doğrudan *vi* komutu ile *ex* programı tam-ekran görsel modunda çalıştırılır oldu.

Yıllar sonra Bram Moolenaar tarafından *vi* kodu geliştirildi ve **vim** (*Vi IMproved*) ortaya çıktı. `vim`, `vi`'ın tüm özelliklerini içerirken, üzerine sözdizimi renklendirme (syntax highlighting), çoklu geri alma (undo), görsel mod (visual mode), eklenti desteği gibi birçok modern özellik eklemiştir. Günümüzde çoğu Linux dağıtımında `vi` komutu aslında `vim`'in daha kısıtlı bir modda çalışan halini veya doğrudan `vim`'i çalıştırır. Bu nedenle, genellikle `vim`'in sunduğu gelişmiş özelliklerden faydalanmak daha pratiktir. Örneklerimizde `vim`'i temel alacağız.

Çoğu sistemde `vim` önyüklü gelir. Eğer kurulu değilse, dağıtımınızın paket yöneticisi ile kolayca kurabilirsiniz:

```bash
# Debian/Ubuntu tabanlı sistemler:
sudo apt update && sudo apt install vim

# RHEL/CentOS/Fedora tabanlı sistemler:
sudo dnf install vim 
# veya eski sürümlerde:
# sudo yum install vim 
```

## Çalışma Modları

vi'ın bir takım çalışma modları vardır, bu aslında *ed*'den kalan bir alışkanlıktır. vi ilk çalıştırıldığında *komut* modunda bulunur, *düzenleme* moduna geçmek için ayrıca işlem yapmanız gerekir. *komut* modundayken tuşlara basarsanız yazı yazamazsınız, ancak kopyalama, silme, dosya içinde gezinme benzeri işlemleri gerçekleştirebilirsiniz.

Dosyamızı `vi` (veya `vim`) ile aşağıdaki gibi açtığımızda, varsayılan olarak \_Komut Modu\_nda başlarız.

```bash
vim crc8.py 
```

*Komut Modu*'ndan *Düzenleme (Insert) Modu*'na geçmek için çeşitli tuşlar kullanılır:

* **i**: İmlecin bulunduğu yerden itibaren eklemeye başlar (insert).
* **a**: İmlecin bulunduğu karakterden *sonra* eklemeye başlar (append).
* **I**: Satırın başına geçer ve eklemeye başlar.
* **A**: Satırın sonuna geçer ve eklemeye başlar.
* **o**: İmlecin bulunduğu satırın *altına* yeni bir boş satır açar ve ekleme moduna geçer.
* **O**: İmlecin bulunduğu satırın *üstüne* yeni bir boş satır açar ve ekleme moduna geçer.

Düzenleme moduna geçtiğinizde, terminalin en alt satırında genellikle **-- INSERT --** veya **-- EKLE --** gibi bir ibare belirir. Bu modda klavyeden yazdıklarınız doğrudan dosyaya eklenir.

Düzenleme modundan çıkıp tekrar *Komut Modu*'na dönmek için klavyenizdeki **ESC** tuşuna basmanız gerekir. **-- INSERT --** yazısı kaybolacaktır. Tüm temel komutlar, silme, kopyalama, yapıştırma işlemleri *Komut Modu*'nda yapılır.

## Temel Komutlar (Komut Modu)

Aşağıdaki komutlar *Komut Modu*'nda iken çalışır. Bazıları doğrudan harf tuşları ile, bazıları ise `:` karakteri ile başlar.

**Çıkış ve Kaydetme:**

* **:q** : Değişiklik yapılmadıysa çıkar (quit).
* **:q!** : Değişiklikleri kaydetmeden çıkmaya zorlar.
* **:w** : Dosyayı kaydeder (write).
* **:wq** veya **:x** veya **ZZ** (Shift+Z iki kere): Dosyayı kaydedip çıkar.
* **:w yeni\_dosya\_adi** : Dosyayı farklı bir isimle kaydeder.

**Navigasyon (Gezinme):**

* **h, j, k, l**: Sol, aşağı, yukarı, sağ yön tuşları gibi çalışır.
* **w**: Sonraki kelimenin başına gider.
* **b**: Önceki kelimenin başına gider.
* **0** (sıfır): Satırın başına gider.
* **$**: Satırın sonuna gider.
* **^**: Satırın başındaki ilk karaktere (boşluk olmayan) gider.
* **gg**: Dosyanın başına gider.
* **G** (Shift+g): Dosyanın sonuna gider.
* **:N** (N bir sayı): N numaralı satıra gider (örneğin `:17`).
* **Ctrl+f**: Bir sayfa aşağı gider (forward).
* **Ctrl+b**: Bir sayfa yukarı gider (backward).

**Silme:**

* **x**: İmlecin üzerindeki karakteri siler.
* **dw**: İmleçten kelimenin sonuna kadar siler (delete word).
* **dd**: İmlecin bulunduğu satırı tamamen siler.
* **D** (Shift+d) veya **d$**: İmleçten satır sonuna kadar siler.

**Kopyalama ve Yapıştırma:**

* **yw**: İmleçten kelimenin sonuna kadar kopyalar (yank word).
* **yy** veya **Y** (Shift+y): İmlecin bulunduğu satırı tamamen kopyalar.
* **p**: Kopyalanan veya silinen metni imleçten *sonra* yapıştırır (paste).
* **P** (Shift+p): Kopyalanan veya silinen metni imleçten *önce* yapıştırır.

**Geri Alma / Yineleme:**

* **u**: Son yapılan değişikliği geri alır (undo).
* **Ctrl+r**: Geri alınan değişikliği yineler (redo).

**Arama:**

* **/aranacak\_metin**: İmleçten itibaren ileriye doğru metin arar. `n` tuşu sonraki eşleşmeye, `N` tuşu önceki eşleşmeye gider.
* **?aranacak\_metin**: İmleçten itibaren geriye doğru metin arar. `n` ve `N` tuşları aynı şekilde çalışır.

**Diğer Modlar:**

* **v**: Görsel Moda (Visual Mode) geçer. Ok tuşları veya navigasyon komutları ile metin seçilebilir. Seçilen metin üzerinde silme (`d`), kopyalama (`y`) gibi işlemler yapılabilir.
* **V** (Shift+v): Satır bazında Görsel Moda geçer.
* **Ctrl+v**: Blok bazında Görsel Moda geçer (dikdörtgen seçim).

**Ayarlar (:** ile başlayan komutlar):

* **:set number** veya **:set nu**: Satır numaralarını gösterir.
* **:set nonumber** veya **:set nonu**: Satır numaralarını gizler.
* **:set hlsearch**: Arama sonuçlarını vurgular.
* **:set nohlsearch**: Arama vurgusunu kaldırır.
* **:syntax on**: Sözdizimi renklendirmeyi açar (genellikle varsayılan olarak açıktır).
* **:syntax off**: Sözdizimi renklendirmeyi kapatır.

**Pencere Yönetimi (:** ile başlayan komutlar):

* **:split** veya **:sp**: Ekranı yatay olarak ikiye böler, aynı dosyayı gösterir.
* **:vsplit** veya **:vsp**: Ekranı dikey olarak ikiye böler, aynı dosyayı gösterir.
* **:sp dosya\_adi**: Ekranı yatay böler ve yeni pencerede belirtilen dosyayı açar.
* **:vsp dosya\_adi**: Ekranı dikey böler ve yeni pencerede belirtilen dosyayı açar.
* **:new**: Yeni boş bir pencere açar.
* **Ctrl+w Ctrl+w** veya **Ctrl+w w**: Pencereler arasında geçiş yapar.
* **Ctrl+w h/j/k/l**: Yön tuşlarına göre pencereler arasında geçiş yapar.
* **:q** (pencere içindeyken): Aktif pencereyi kapatır.
* **:only**: Aktif pencere dışındaki tüm pencereleri kapatır.

Bu komutlar `vim`'in temel kullanımını kapsar. `vim` çok daha fazla özelliğe ve komuta sahiptir. Daha fazla bilgi için komut modundayken `:help` yazarak `vim`'in kendi yardım sistemine başvurabilirsiniz veya `vimtutor` komutunu çalıştırarak interaktif bir eğitim alabilirsiniz.


# Sıkıştırılmış Dosyalar

## tar Dosyaları

TAR dosyaları, birden fazla dosyanın tek bir dosya haline getirilmesine yarar. Eskiden daha yaygın kullanılan kasetler, özellikle dosyaların arşivlenmesi için sıralı okuma/yazma işlemi yapmaktadır. Bu tip cihazlara dosyaları aralarında boşluk olmadan, sıralı bir biçimde okuyup yazabilmek için dosyaları bir araya getirip tek bir dosya haline getirmek gerekmektedir. tar programı TAR dosyası oluşturarak bu işi yapar. İsmi bu yüzden **T**ape **AR**chive sözcüklerinin kısaltmasından gelmektedir. Oluşturulan dosyalara genellikle *tarball* denilir. Burada ufak bir kelime oyunu yapılmaktadır. Tarball aslında denizde veya okyanusta katılaşarak topaklaşan petrol kalıntısına denilir. Bu tip topaklaşmalar sırasında petrol, civarındaki başka parçacıkları da bir araya getirdiği için bu benzetme yapılmıştır.

TAR dosyaları, birden fazla dosyayı bir araya getirmek için kullanılır, ancak sıkıştırma gerçekleştirmezler. tar programı UNIX'in 7. versiyonunda geliştirilmiştir ve ilerileyen yıllarda tar dosyalarının yapısı standartlaştırılmıştır. Her ne kadar tar dosyaları sıkışmış dosyalar olmasa da, tar programı oluşturduğu dosyayı daha sonra sıkıştırabilecek, veya sıkıştırılmış tar dosyalarını açabilecek yeteneklere sahiptir.

### tarball

Basit bir tarball dosyası aşağıdaki gibi oluşturulabilir.

```bash
tar -cvf tarball.tar 03-debug.txt putty.log
```

Burada `03-debug.txt` ve `putty.log` dosyalarını birleştirip, `tarball.tar` isimli bir dosya oluşturulmaktadır. `-c` parametresi *create*'in kısaltması olarak, bir tar dosyası oluşturulacağını belirtmektedir. `-v` parametresi, hemen her GNU/Linux programında olduğu gibi *verbose* anlamına gelir, programın yaptığı işlem hakkında bilgi vermesini sağlar. `-f` parametresi ise kendisinden sonra dosya isminin belirtileceği anlamıan gelmektedir, *file* sözcüğünün kısaltmasıdır.

```bash
tar -xvf tarball.tar
```

Yukarıdaki örnekteyse, *create* yerine *extract*'in kısaltması olan `-x` parametresi kullanılmıştır. Tahmin edeceğiniz üzere burada da sadece `tarball.tar` dosyası "açılmaktadır".

```bash
tar -xvf tarball.tar putty.log
```

Eğer `tarball.tar` dosyası içinden bütün dosyaları değil de, sadece `putty.log` dosyasını çıkarmak istersek, yukarıdaki gibi çıkartılacak dosyayı parametre olarak sağlayabiliriz.

Yukarıdaki gibi, bir tarball içinden sadece belirli bir dosyayı çıkarmak istiyorsak, ilgili tarball'un içeriğini bilmemiz gerekir. Bunun için *list*'in kısaltması olarak kullanılan `-t` parametresini aşağıdaki gibi kullanmak yeterli olacaktır.

```bash
eaydin@dixon ~/calisma/zip $ tar -tvf tarball.tar 
-rwxrwxr-- eaydin/eaydin 20728203 2015-11-20 16:33 03-debug.txt
-rwxrwxr-- eaydin/eaydin   112548 2015-11-20 17:49 putty.log
```

Oluşturulan tarball dosyalarında, dosyaların izinleri korunmaz. Mevcut sistemdeki izinleri korumasını istersek, *preserve permissions*'ın kısaltması olan `-p` parametresini de eklemek gerekecektir.

```bash
tar -cvfp tarball.tar *.log
```

Mevcut tar dosyasına başka dosya eklemek için, *append* anlamına gelen `-r` parametresi kullanılır.

```bash
tar -rf tarball.tar 03-debug.txt
```

Unutulmaması gereken nokta, tarball dosyasına yeni bir dosya eklemek için, ilgili tarball'un sıkıştırılmış olmaması gerekir. Sıkıştırılmış dosyalara (tar.gz, tar.bz2) sonradan dosya ekleyemezsiniz, sıkıştırma algoritmalarının doğası gereği, dosyayı yeniden oluşturmanız gerekir.

### tar.gz

Oluşturulacak tarball dosyasının sıkıştırılmış bir dosya olacağını belirtmek için, daha önce kullandığımız standart parametreler arasına, *zip*'in kısaltması olarak `-z` eklenmesi gerekir.

```bash
tar -cvzf tarball.tar.gz 03-debug.txt putty.log
```

Benzer şekilde sıkıştırılmış bir dosyayı açacağımız zaman da `-z` ile tar programına açacağı dosyanın sıkıştırılmış bir dosya olduğunu belirtmek gerekir.

```bash
tar -xvzf tarball.tar.gz
```

Bu parametre ile kullanılan algoritma, GNU Zip algoritması olduğu için, aslında arka planda birazdan göreceğimiz `gzip` programını kullanır. Bu yüzden genellikle GNU Zip ile sıkıştırılmış tarball dosyalarına `.tar.gz` veya `.tgz` uzantısı verilir.

### tar.bz2

Eğer sıkıştırma algoritması olarak GNU Zip yerine `bzip2` kullanılmasını istersek, `-z` yerine `-j` parametresini hem tarball oluşturulurken, hem de açılırken kullanmak gerekir. Bu format için yaygın uzantılar `.tar.bz2` veya `.tbz2`'dir.

```bash
tar -cvjf tarball.tar.bz2 03-debug.txt putty.log
```

```bash
tar -xvjf tarball.tar.bz2
```

### tar.xz

Daha yüksek sıkıştırma oranı sunan `xz` algoritmasını kullanmak için `-J` parametresi kullanılır. Uzantı olarak genellikle `.tar.xz` veya `.txz` kullanılır.

```bash
tar -cvJf tarball.tar.xz *.log
```

```bash
tar -xvJf tarball.tar.xz
```

### tar.zst

Modern ve hızlı bir sıkıştırma algoritması olan `zstd` (Zstandard) kullanmak için genellikle `-I zstd` veya `--zstd` parametresi kullanılır (kullanılan `tar` sürümüne bağlı olabilir). Uzantı olarak `.tar.zst` veya `.tzst` kullanılır.

```bash
# --zstd kullanımı (daha yeni tar sürümlerinde)
tar -cv --zstd -f tarball.tar.zst *.log
tar -xv --zstd -f tarball.tar.zst

# -I kullanımı (bazı eski sürümlerde de çalışabilir)
# tar -cv -I zstd -f tarball.tar.zst *.log
# tar -xv -I zstd -f tarball.tar.zst
```

**Önemli Not:** Modern `tar` sürümleri, bir arşivi açarken (`-x` kullanılırken) sıkıştırma türünü genellikle otomatik olarak algılayabilir. Bu nedenle, çoğu zaman `-z`, `-j`, `-J` gibi sıkıştırma belirtme parametrelerini açma işlemi sırasında kullanmak gerekmeyebilir. Sadece `-xvf arsiv_dosyasi` komutu yeterli olabilir. Ancak, oluştururken doğru sıkıştırma parametresini belirtmek önemlidir.

## Sıkıştırılmış Dosyalar

### gzip

GNU Zip dosyaları, sıkıştırma amacıyla kullanılır. Tek dosyayı girdi olarak alır. Dolayısıyla birden fazla dosyanın tek paket halinde sıkıştırılması gerekiyorsa, yukarıda gördüğümüz örneklerdeki gibi, önce tarball oluşturulup, sonra gzip ile sıkıştırmak gerekir.

Aşağıda, tek dosyanın doğrudan sıkıştırılması gerçekleştirilir.

```bash
gzip putty.log
```

Bu işlemin sonucunda `putty.log.gz` isimli bir dosya oluşur ve `putty.log` dosyası silinir.

Eğer mevcut dosyanın korunması isteniyorsa, `-c` parametresiyle oluşturulan verinin standart çıktıya yazdırılması sağlanabilir. Standart çıktı hakkında detaylı bilgi kitabın ilerleyen bölümlerinde yer almaktadır.

```bash
gzip -c putty.log > putty.log.gz
```

Oluşan bir dosyayı "açmak" içinse, GNU Unzip'in kısaltması olan `gunzip` kullanılır.

```bash
gunzip putty.log.gz
```

Veya gzip'in *decompress* anlamına gelen `-d` parametresi kullanılabilir.

```bash
gzip -d putty.log.gz
```

### bz2

```bash
bzip2 putty.log
```

Sıkıştırılmamış dosyayı siler.

```bash
bunzip putty.log.bz2
```

```bash
bzip2 -d putty.log.bz2
```

tar, gz, bz2 dosyaları için kullanabileceğiniz bir cheat-sheet [şurada](http://www.cyberciti.biz/howto/question/general/compress-file-unix-linux-cheat-sheet.php) mevcut. (Not: Bu kaynakta `xz` ve `zstd` gibi daha yeni formatlar bulunmayabilir.)

### zip ve unzip

```bash
zip log-dosyalari.zip *
```

```bash
eaydin@dixon ~/calisma/zip $ unzip -l log-dosyalari.zip 
Archive:  log-dosyalari.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
 20728203  2015-11-20 16:33   03-debug.txt
   112548  2015-11-20 17:49   putty.log
---------                     -------
 20840751                     2 files
```

```bash
 eaydin@dixon ~/calisma/zip $ unzip log-dosyalari.zip -d yeni-dizin
Archive:  log-dosyalari.zip
  inflating: yeni-dizin/03-debug.txt  
  inflating: yeni-dizin/putty.log
```

### rar ve unrar

```bash
rar a arsiv.rar *.log
```

```bash
eaydin@dixon ~/calisma/zip $ unrar l arsiv.rar 

UNRAR 5.00 beta 8 freeware      Copyright (c) 1993-2013 Alexander Roshal

Archive: arsiv.rar
Details: RAR 4

 Attributes      Size    Date   Time   Name
----------- ---------  -------- -----  ----
 -rwxr-xr--  20728203  03-12-15 10:51  debug.log   
 -rwxr-xr--    112548  20-11-15 17:49  putty.log   
----------- ---------  -------- -----  ----
             20840751                  2
```

```bash
unrar e arsiv.rar
```

**Not:** `rar` formatı ve sıkıştırma aracı tescilli bir yazılımdır. `unrar` aracı genellikle ücretsiz olarak sunulsa da, `rar` dosyası oluşturmak için lisans gerekebilir. Diğer formatlar (`gz`, `bz2`, `xz`, `zst`, `zip`) genellikle açık kaynaklı ve ücretsiz araçlarla yönetilir.

## Z Komutları

GNU/Linux sistemlerde özellikle log dosyalarının sıkıştırılarak saklanması yaygın tekniklerdir. Sıkıştırılmış bu dosyalar içinde arama yapmak, dosyanın bir kısmını okumak veya dosyalar arası farklılıkları incelemek gerekebilir. Bu tip işlemler için sıkça kullanılan komutların **z** ile başlayan versiyonları geliştirilmiştir.

`zcat`, `zless`, `zmore`, `zgrep`, `zegrep`, `zdiff` komutlarını bu tip dosyalar üzerinde çalışmak için kullanabilirsiniz.


# Standart Girdi ve Çıktı

GNU/Linux ve benzeri POSIX sistemlerin en güçlü olduğu yönlerden birisi, programların standart girdi ve çıktılarının yönlendirilmesidir. Özellikle birden fazla programın işlemlerini birbirlerine kolayca gönderebilme gücü sağlayan bu yöntem, aslında UNIX'in oluşturulduğu dönemdeki temel felsefeleri en iyi yansıtan özelliklerinden biridir.

1978'de yayımlanan *The Bell System Technical Journal'ın UNIX Time-Sharing System* dokümanının önsözünde Douglas McIlroy, UNIX'in tasarlanması ve kullanılmasında temel alınan kritik noktaları 4 madde halinde listeler. Bu maddelerden ilki ilerleyen yıllarda çok popüler olmuştur. Maddenin tam hali şu şekildedir:

> Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new "features".

Bu maddede McIlroy, bir program yazılırken, bu programın *tek* *bir şeyi iyi yapması gerektiğini* vurgular. Yeni bir iş yapılacağı zaman, mevcut programa yeni "özellikler" eklemek yerine, yeni bir program yazılmasının daha doğru olduğunu savunur.

Önsözde paylaşılan maddelerden ikincisinin tam hali ise şu şekildedir:

> Expect the output of every program to become the input to another, as yet unknown, program. Don't clutter output with extraneous information. Avoid stringently columnar or binary input formats. Don't insist on interactive input.

Bu madde başlı başına çok fazla şey söyler, ve bir süre GNU/Linux sistemler üzerinde yazılmış programları kullanan herkes, aslında bu maddelerin çoğu programda uygulandığını görecektir. Öncelikle bu bölümde bahsedeceğimiz girdi ve çıktıların yönlendirilmesi gerekliliği, maddenin ilk cümlesinde ifade edilmiştir. McIlroy, her programın çıktısının aynı zamanda girdi olarak tasarlanması gerektiğini, hatta ne iş yaptığını bilmediği bir programın girdisi olarak kullanılabileceğinin gözönünde bulundurulması gerektiğini belirtir. Çıktıların gereksiz bilgilerle kirletilmemesi gerektiğini, kolon bazlı girdilerin veya binary girdilerin dayatılmasından kaçınılması gerektiğini ifade eder. Ayrıca, gerekmediğinde *etkileşimli girdiden* kaçınılması gerektiğini belirtir. Çünkü etkileşimli girdi, bir programa standart girdi olarak veri göndermenin zorlaşması demektir.

Eğer girdi ve çıktı yönlendirmeleri ile ilgili hiç tecrübeniz yoksa, yukarıdaki satırlar size soyut gelebilir. Bu bölümü okuduktan sonra yukarıdaki anlayışın ne ifade ettiği biraz daha netleşecektir. Ayrıca kitabın ilerleyen bölümlerini okuduktan sonra tekrar dönüp bu felsefeyi okumanızda fayda olabilir.


# Standart Çıktı

Eğer bu *standart çıktı* söylemi sizin için hiçbir şey ifade etmiyorsa, önce *standart* sözcüğünü ortadan kaldıralım: Bir programın *çıktısı* ne demek?

Terminal üzerinden herhangi bir komut çalıştırdığınızda, aslında o program bir *şey* üretecektir. Genellikle bu ürettiği *şeyi* ekrana yazdığını görürüz. Örneğin `ls` komutu, bulunduğumuz dizindeki dosyaları gösterir.

```
eaydin@eaydin-vt ~/devel/pgpoolwatch $ ls
args.txt.sample    LICENSE      poolstatus.py  repmgrwatch.py  sendmail.py  test
config.ini.sample  pgpwatch.py  README.md      scripts         services
```

Burada ls komutu, aslında `LICENSE`, `pgpwatch.py`, `scripts` gibi dosya ve dizin isimlerini bize çıktı olarak sunmuştur. Örneğin `ls -l` yazsaydık, farklı bir çıktı sunacaktı.

```
eaydin@eaydin-vt ~/devel/pgpoolwatch $ ls -l 
total 92
-rw-rw-r-- 1 eaydin eaydin   203 Jan  8 14:30 args.txt.sample
-rw-rw-r-- 1 eaydin eaydin   401 Jan  8 15:51 config.ini.sample
-rw-r--r-- 1 eaydin eaydin  1070 Dec 18 16:32 LICENSE
-rwxrwxr-x 1 eaydin eaydin 12908 Jan  8 14:30 pgpwatch.py
-rwxrwxr-x 1 eaydin eaydin 15274 Jan  8 14:30 poolstatus.py
-rw-rw-r-- 1 eaydin eaydin 13491 Jan  8 14:30 README.md
-rwxrwxr-x 1 eaydin eaydin 12184 Jan  8 14:30 repmgrwatch.py
drwxrwxr-x 2 eaydin eaydin  4096 Jan  8 14:30 scripts
-rwxrwxr-x 1 eaydin eaydin  5955 Jan  8 14:30 sendmail.py
drwxrwxr-x 2 eaydin eaydin  4096 Jan  8 16:04 services
drwxrwxr-x 2 eaydin eaydin  4096 Jan  8 14:30 test
```

Her iki durumda da `ls` programına, çıktıyı nereye yazacağını söylemiyoruz, bu yüzden `ls`, *standart olan çıktıya* yazıyor. Bu durumda da bizim terminal ekranımız.

UNIX sistemlerde, bu çıktıyı "standart olmaktan çıkarma" amacıyla, standart çıktıyı farklı bir yere yönlendirmenin faydalı olacağı görülmüştür. Örneğin yukarıdaki `ls -l` sonucunu, standart çıktı yerine bir dosyaya yönlendirebiliriz.

```
eaydin@eaydin-vt ~/devel/pgpoolwatch $ ls -l > /home/eaydin/ls_cikti
eaydin@eaydin-vt ~/devel/pgpoolwatch $
```

Farkındaysanız, artık ekranda `ls -l` komutunun sonucunu görmüyoruz, çünkü programın standart çıktısını `/home/eaydin/ls_cikti` dosyasına yönlendirdik. Böyle olunca standart çıktısı olan terminalimize veri yazmadı.Eğer gidip `/home/eaydin/ls_cikti` dosyasının içeriğini okursak, biraz önceki sonucun aynısını görürüz.

```
eaydin@eaydin-vt ~/devel/pgpoolwatch $ cat /home/eaydin/ls_cikti 
total 92
-rw-rw-r-- 1 eaydin eaydin   203 Jan  8 14:30 args.txt.sample
-rw-rw-r-- 1 eaydin eaydin   401 Jan  8 15:51 config.ini.sample
-rw-r--r-- 1 eaydin eaydin  1070 Dec 18 16:32 LICENSE
-rwxrwxr-x 1 eaydin eaydin 12908 Jan  8 14:30 pgpwatch.py
-rwxrwxr-x 1 eaydin eaydin 15274 Jan  8 14:30 poolstatus.py
-rw-rw-r-- 1 eaydin eaydin 13491 Jan  8 14:30 README.md
-rwxrwxr-x 1 eaydin eaydin 12184 Jan  8 14:30 repmgrwatch.py
drwxrwxr-x 2 eaydin eaydin  4096 Jan  8 14:30 scripts
-rwxrwxr-x 1 eaydin eaydin  5955 Jan  8 14:30 sendmail.py
drwxrwxr-x 2 eaydin eaydin  4096 Jan  8 16:04 services
drwxrwxr-x 2 eaydin eaydin  4096 Jan  8 14:30 test
```

Öyleyse, standart çıktı yönlendirme işlemini **>** işaretiyle gerçekleştiriyoruz. Böylece standart çıktıya sonuç döndüren programların tamamının çıktılarını bir dosyaya yönlendirebiliriz.

Standart çıktı yönlendirmek için kullandığımız **>** işareti, hedef dosya bulunmazsa oluşturur. Eğer hedef dosya bulunuyorsa, dosyanın içeriğini tamamen siler ve yeni sonucu yazar. Eğer hedef dosyanın içeriğinin silinmesini istemiyorsak, ancak yeni sonucun dosyanın *sonuna eklenmesini* istiyorsak, bunun için **>>** işaretini kullanmamız gerekir.

Biraz önceki örneğimizde kullandığımız çıktı dosyasının sonuna, farklı bir dizinin çıktısını da eklemek isteseydik, şöyle bir işlem yapabilirdik.

```
eaydin@eaydin-vt ~/devel $ cd diskalert/
eaydin@eaydin-vt ~/devel/diskalert $ ls -l >> /home/eaydin/ls_cikti
eaydin@eaydin-vt ~/devel/diskalert $ cat /home/eaydin/ls_cikti
total 92
-rw-rw-r-- 1 eaydin eaydin   203 Jan  8 14:30 args.txt.sample
-rw-rw-r-- 1 eaydin eaydin   401 Jan  8 15:51 config.ini.sample
-rw-r--r-- 1 eaydin eaydin  1070 Dec 18 16:32 LICENSE
-rwxrwxr-x 1 eaydin eaydin 12908 Jan  8 14:30 pgpwatch.py
-rwxrwxr-x 1 eaydin eaydin 15274 Jan  8 14:30 poolstatus.py
-rw-rw-r-- 1 eaydin eaydin 13491 Jan  8 14:30 README.md
-rwxrwxr-x 1 eaydin eaydin 12184 Jan  8 14:30 repmgrwatch.py
drwxrwxr-x 2 eaydin eaydin  4096 Jan  8 14:30 scripts
-rwxrwxr-x 1 eaydin eaydin  5955 Jan  8 14:30 sendmail.py
drwxrwxr-x 2 eaydin eaydin  4096 Jan  8 16:04 services
drwxrwxr-x 2 eaydin eaydin  4096 Jan  8 14:30 test
total 32
drwxr-xr-x 4 eaydin eaydin 4096 Dec 18 16:32 build
drwxr-xr-x 2 eaydin eaydin 4096 Dec 18 16:32 DiskAlert
drwxr-xr-x 2 eaydin eaydin 4096 Dec 18 16:32 DiskAlert.egg-info
drwxr-xr-x 2 eaydin eaydin 4096 Dec 18 16:32 dist
drwxr-xr-x 2 eaydin eaydin 4096 Dec 18 16:32 etc
-rw-r--r-- 1 eaydin eaydin 1070 Dec 18 16:32 LICENSE
-rw-r--r-- 1 eaydin eaydin  593 Dec 18 16:32 README.md
-rw-r--r-- 1 eaydin eaydin 1465 Dec 18 16:32 setup.py
```

Yukarıdaki örnekte, önce `/home/eaydin/devel/diskalert` dizinine gidiyoruz. Daha sonra `ls -l` komutunu çalıştırıp, çıktısını `/home/eaydin/ls_cikti` dosyasına yönlendiriyoruz, ancak standart çıktının önceki dosyayı silmeden, mevcut verileri koruyup, yeni veriyi dosyanın sonuna eklemesi için **>>** işareti ile çıktı yönlendirmesi yapıyoruz. Sonra `/home/eaydin/ls_cikti` dosyasının içeriği `cat` ile okuyoruz (aslında `cat` ile dosyanın içeriğini *standart çıktıya yazdırıyoruz*) ve hem `pgpoolwatch`, hem de `diskalert` dizinlerinin içeriğini görüyoruz.

Modern GNU/Linux sistemlerinde, eğer özel bir durum söz konusu değilse, genellikle standart çıktı kullanıcının ekranıdır. Yani programlar standart çıktı olarak monitörünüzü kullanır. Teknik detaylarına girdiğimizde aslında "kullandığınız terminal standart çıktıdır" demek daha doğru olabilir ancak şu aşamada bunu düşünmenize gerek yok. Bir GNU/Linux sistemini istersek öyle ayarlayabiliriz ki, standart çıktısı terminal/monitör olmak yerine örneğin yazıcı (*printer*) olabilir. Örneğin dijital ekranı olmayan bir ödeme cihazımız (POS cihazı) için böyle bir durum söz konusu olabilir.


# Standart Girdi

UNIX dünyasında, programların standart çıktıları gibi, aslında standart girdileri de vardır. Biraz önceki örneğimizde `cat` programı ile `ls_cikti` dosyasının içeriğini görüntülerken, okunacak veriyi standart girdi olarak sunmayıp, aslında parametre olarak gönderdik. Yani `cat /home/eaydin/ls_cikti` yazdığımız zaman, aslında `cat` programı ilk parametresi olan `/home/eaydin/ls_cikti` değerini okudu. Eğer bu dosyayı parametrik olarak değil de, standart girdi olarak sunmak isteseydik, şöyle bir işlem yapmamız gerekirdi:

```
eaydin@eaydin-vt ~ $ cat < ls_cikti
total 92
-rw-rw-r-- 1 eaydin eaydin   203 Jan  8 14:30 args.txt.sample
-rw-rw-r-- 1 eaydin eaydin   401 Jan  8 15:51 config.ini.sample
-rw-r--r-- 1 eaydin eaydin  1070 Dec 18 16:32 LICENSE
-rwxrwxr-x 1 eaydin eaydin 12908 Jan  8 14:30 pgpwatch.py
-rwxrwxr-x 1 eaydin eaydin 15274 Jan  8 14:30 poolstatus.py
-rw-rw-r-- 1 eaydin eaydin 13491 Jan  8 14:30 README.md
-rwxrwxr-x 1 eaydin eaydin 12184 Jan  8 14:30 repmgrwatch.py
drwxrwxr-x 2 eaydin eaydin  4096 Jan  8 14:30 scripts
-rwxrwxr-x 1 eaydin eaydin  5955 Jan  8 14:30 sendmail.py
drwxrwxr-x 2 eaydin eaydin  4096 Jan  8 16:04 services
drwxrwxr-x 2 eaydin eaydin  4096 Jan  8 14:30 test
total 32
drwxr-xr-x 4 eaydin eaydin 4096 Dec 18 16:32 build
drwxr-xr-x 2 eaydin eaydin 4096 Dec 18 16:32 DiskAlert
drwxr-xr-x 2 eaydin eaydin 4096 Dec 18 16:32 DiskAlert.egg-info
drwxr-xr-x 2 eaydin eaydin 4096 Dec 18 16:32 dist
drwxr-xr-x 2 eaydin eaydin 4096 Dec 18 16:32 etc
-rw-r--r-- 1 eaydin eaydin 1070 Dec 18 16:32 LICENSE
-rw-r--r-- 1 eaydin eaydin  593 Dec 18 16:32 README.md
-rw-r--r-- 1 eaydin eaydin 1465 Dec 18 16:32 setup.py
```

Gördüğünüz gibi, burada standart çıktı işaretinin tersini (**<**) kullanıyoruz. Standart girdilerde, *üzerine yazma* gibi bir durum söz konusu olmadığından, **<<** gibi bir notasyona gerek kalmaz.

Yukarıda kullandığımız `cat` programı örneği, her ne kadar standart girdi kullanmış olsa da, pek bir anlam ifade etmeyebilir. En nihayetinde kullanıcı açısından dosya ismini parametrik olarak belirtmek ile standart girdi olarak belirtmek arasında bir fark bulunmamaktadır. Aslında teknik olarak bir fark var ancak buna birazdan değineceğiz.

`cat` programı eğer standart girdiden veri beklentisi içindeyse, `cat` programını hiçbir parametre kullanmadan çalıştırırsak ne olur? Bu sorunun cevabını `cat` programı çalıştırıp "Bu bir cümle" yazarak deneyelim.

```
eaydin@k9 ~ $ cat
Bu bir cümle
Bu bir cümle
^C
```

Yukarıda ne olup bittiğine bir bakalım: Hiçbir parametre göndermeden `cat` programını çalıştırıyoruz. Sonra program bizden (standart girdiden) bir girdi bekliyor. Biz de "Bu bir cümle" yazıp ENTER tuşuna basıyoruz. Ardından ekranda bir satır daha kendiliğinden beliriyor ve bizim yazdığımız cümlenin aynısını yazıyor. Sonra CTRL+c tuşu ile programı sonlandırıyoruz.

Bu örnekteki ikinci "Bu bir cümle" satırının yazmasının sebebi, `cat` programının işlevinde yatmaktadır. Standart girdi veya parametrik dosya belirtilmesi farketmeksizin `cat` programı, kendisine gönderilen verinin standart çıktıya yazdırılması işlemini gerçekleştirdiği için, biz "Bu bir cümle" yazıp programa bunu sunduktan sonra, program bunu standart çıktıya yazıyor. Dolayısıyla ekranda iki kez görmüş oluyoruz.

Eğer `cat` programını çalıştırırken standart çıktıyı bir dosyaya yönlendirseydik, durum farklı olurdu.

```
eaydin@k9 ~ $ cat > deneme
Bu da başka bir cümle
^C
```

Burada programa standart girdiden veri gönderdik, ancak standart çıktıyı `deneme` dosyasına yönlendirdiğimiz için, ekranımızda ikinci kez görmedik. `deneme` dosyasının içeriğini okuyacak olursak ne beklediğimiz aşikar sanırım.

```
eaydin@k9 ~ $ cat deneme
Bu da başka bir cümle
```

Bütün bu örneklerin hala bir şey ifade etmediğinin farkındayız. Çünkü `cat`, zaten dosya okuma amacı güden bir program. Bunun yerine daha sık kullanılan bir örnek olan, MySQL veritabanının komut satırı aracı `mysql` programının kullanımına bakalım.

MySQL ile ilgili detaylar kitabımızın farklı bir bölümünde anlatılmakta ancak kısaca programın bir veritabanının yapısını komut satırından yönetmeye olanak sağladığını belirtelim. `mysql` programı etkileşimli bir programdır, yani Douglas McIlroy'un ikinci maddede bahsettiği, aslında kaçınmamız gereken program tiplerinden birisidir. Ancak bir veritabanını yönetmenin en kullanışlı yollardından birinin bu olduğu unutulmamalıdır. `mysql` programını doğru parametrelerle çalıştırıp veritabanına bağlandığımızda, bizi kendi kabuğu (etkileşimli ortamı) karşılar.

```
[root@emre ~]# mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 160953
Server version: 5.5.50 MySQL Community Server (GPL)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```

Burada örneğin, mevcut veritabanlarını listeletmek için, `show databases` komutunu girmemiz gerekir.

```
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| veriteknik         |
| sanallastirma.com  |
| mysql              |
| wordpress          |
+--------------------+
5 rows in set (0.01 sec)
```

Aslında, buradaki `show databases` bilgisini, `mysql` komutuna standart girdiden, yani klavyemizden girmiş bulunduk.

Bunun yerine, bir metin dosyasına `show databases` yazıp, bu metin dosyasını `mysql` programına standart girdi olarak sunabilirdik. `komutlar` dosyasının içeriği `show databases` olmak üzere, aşağıdaki gibi bir notasyonla, `mysql` programına komutlarımızı gönderebiliriz.

```
[root@emre ~]# mysql < komutlar
Database
information_schema
veriteknik
sanallastirma.com
mysql
wordpress
```

Çıktılardaki ufak fark (tablolu yapı, kaç satır döndüğü vs.) sizi yanıltmasın. Bu tamamen `mysql` programının ayarlarıyla ilgili. Burada esas dikkat edilmesi gereken nokta, MySQL geliştiricilerinin, programlarını standart girdiden veri okuyabilecek şekilde yazmış olması. Bu açıdan bakınca, aslında David McIlroy'un ikinci maddesi ile uyumlu bir yazılım ortaya çıkmış oluyor. Program, *etkileşimli girdi konusunda ısrarcı olmuyor*. Ayrıca çıktıda, yine McIlroy'un bahsettiği gibi "gereksiz tablolu yapılar" bulunmuyor.

MySQL bir yana, hemen her veritabanı programı bu şekilde çalışmaktadır. Bu özellikle de veritabanlarına yedeklerin yüklenmesi konusunda kullanılan yöntemlerden birisidir. Aslında bir veritabanı yedeği aldığınızda, size bir dizi komut çıktısı verir. Bu çıktıyı dilediğiniz gibi şekillendirebilir, ve yeniden programlara standart girdiden sunabiliriniz.

Eğer `mysql` programına komutları dosya içerisinden değil de, doğrudan terminal ile sunmak istersek, **<<<** notasyonunu kullanabiliriz. Biraz önceki örneğimizde komutlar dosyasının içerisine `show databases` yazıp, `komutlar` dosyasını standart girdi olarak sunmuştuk. Aslında bu dosyayı hiç oluşturmadan aşağıdaki gibi bir yöntem de izleyebilirdik.

```
[root@emre ~]# mysql <<< 'show databases'
Database
information_schema
veriteknik
sanallastirma.com
mysql
wordpress
```

**Here Documents (`<<`)**

`<<<` (here string) tek satırlık veya basit girdiler için kullanışlıdır. Birden fazla satırdan oluşan girdiyi doğrudan komut satırında veya bir betik içinde standart girdi olarak sağlamak için "here document" (`<<`) yapısı kullanılır. Bu yapıda, bir sınırlayıcı (delimiter) belirlenir ve bu sınırlayıcı tekrar tek başına bir satırda yazılana kadar arasındaki tüm satırlar komuta standart girdi olarak gönderilir.

Örnek:

```bash
# 'EOF' sınırlayıcı olarak kullanılıyor
mysql << EOF
show databases;
use wordpress;
show tables;
EOF
```

Bu komut çalıştırıldığında, `show databases;`, `use wordpress;` ve `show tables;` komutları sırasıyla `mysql` programına standart girdi olarak gönderilir. Sınırlayıcı (`EOF`) herhangi bir kelime olabilir, ancak genellikle `EOF` (End Of File) kullanılır.

Hatırlarsanız bu bölümde `cat` programına parametrik kullanım ve standart girdi ile veri sağlanmasının kullanıcı açısından pek bir fark yaratmadığını, ancak ufak bir farklılığı olduğundan bahsetmiştik.

`cat dosya-ismi` kullanımında, önce `cat` programı çalıştırılır, `cat` programı da parametreleri hangi sırada nasıl okuyorsa ona göre ilgili işlemleri yapar. Ancak `cat < dosya-ismi` kullanımında, kabuk (*shell*) önce `dosya-ismi` dosyasını yüklemeye çalışır, eğer bu dosya mevcut değil veya kullanıcı tarafından erişilemez durumdaysa, hata verir ve `cat` programını hiç çalıştırmaz bile. Bu, özellikle `cat` gibi küçük programlarda hissedilmeyen etkilere sebep olur ancak `mysql` veya çok daha büyük bir programın her defasında boş yere çağırılmasına engel olabileceği için, aslında kabuk programlamada mümkünse kullanılması gereken yöntemlerden birisidir ve doğru kullanıldığında bazı noktalarda sisteminizin daha verimli çalışmasını sağlayabilir.

Standart girdinin **<** notasyonu ile kullanımı, yıllarca UNIX sistemler yönetmiş bir kişinin bile çok nadir karşılaştığı durumlar olabilir. Bu kitapta da özellikle **crontab** ve **netcat** bölümlerinde birkaç örneği dışında denk gelmemeniz olası. Ancak standart girdinin ne işe yaradığının anlaşılması, özellikle birazdan göreceğimiz **pipe** mekanizmasının anlaşılmasında belkemiği görevi görmektedir.


# UNIX Pipeline

## UNIX Pipeline

Douglas McIlroy, işletim sistemindeki programların (veya parçacıkların) birer standart girdisinin ve standart çıktısının olması gerektiği fikrini aslında yukarıdaki örneklerde bahsettiğimiz gibi sadece dosya yönlendirme amacıyla geliştirmemiştir. McIlroy'un amacı, aslında programların birbirleriyle, arada geçici bir dosya veya kullanıcı müdahalesine gerek olmaksızın veri akışının sağlanmasıdır. Bunu yaparken de, bir programın çıktısının diğer programın girdisi olarak yönlendirilmesini kurgulamıştır. McIlroy bu metodolojiyi ilk defa 1973'te kurgulamıştır ve Ken Thompson,`pipe()`sistem çağrısını UNIX versiyon 3 üzerinde uyarlamıştır. Bunu yaparken de yönlendirme işareti olarak`|`kullanılmıştır. McIlroy, bu karakterin kullanımını Thompson'ın geliştirdiğini belirtir. Bu yatak çubuk, aslında bir *boru (pipe)* olarak düşünülünce, tıpkı bir su tesisatındaki boru hattı gibi, bir noktadan giren bilginin, diğer noktadan çıkmasını sağladığı için *pipeline* terminolojisini doğurmuştur.

Örneğin`less`programı, aslında kendisine sağlanan bilginin terminal ekranına sığacak şekilde parçalanmasını sağlar. Tıpkı`cat`programında olduğu gibi, parametrik kullanımla dosya adı belirtilebilir, veya standart girdi olarak veri sağlanabilir.

Eğer çok fazla dosya içeren bir dizin içerisinde`ls -l`komutunu çalıştırırsak, standart çıktı içerisinde kaybolabiliriz. Bunun için`ls -l`komutunun çıktısını,`less`programına girdi olarak sunabiliriz. Bunun için yapmamız gereken tek şey, aralarında *pipe* işaretini kullanmak olacaktır.

```
root@ubuntu:/mnt/backups/orthogonal/# ls -l | less
total 7019320
-rwxr-xr-x 1 root root     15099 May 23  2016 E28b30_0HGK030HF2015COG.aux
-rwxr-xr-x 1 root root  77772699 May 23  2016 E28b30_0HGK030HF2015COG.ecw
-rwxr-xr-x 1 root root     15099 May 23  2016 E28b40_0HGK030HF2015COG.aux
-rwxr-xr-x 1 root root  13464608 May 23  2016 E28b40_0HGK030HF2015COG.ecw
-rwxr-xr-x 1 root root     15099 May 23  2016 E28c10_0HGK030HF2015COG.aux
-rwxr-xr-x 1 root root 260127268 May 23  2016 E28c10_0HGK030HF2015COG.ecw
-rwxr-xr-x 1 root root     15099 May 23  2016 E28c20_0HGK030HF2015COG.aux
-rwxr-xr-x 1 root root 261387832 May 23  2016 E28c20_0HGK030HF2015COG.ecw
-rwxr-xr-x 1 root root     15099 May 23  2016 E28c30_0HGK030HF2015COG.aux
-rwxr-xr-x 1 root root 262376992 May 23  2016 E28c30_0HGK030HF2015COG.ecw
-rwxr-xr-x 1 root root     15099 May 23  2016 E28c40_0HGK030HF2015COG.aux
-rwxr-xr-x 1 root root 250611074 May 23  2016 E28c40_0HGK030HF2015COG.ecw
-rwxr-xr-x 1 root root     15099 May 23  2016 E28d10_0HGK030HF2015COG.aux
-rwxr-xr-x 1 root root  12259662 May 23  2016 E28d10_0HGK030HF2015COG.ecw
-rwxr-xr-x 1 root root     15099 May 23  2016 E28d20_0HGK030HF2015COG.aux
-rwxr-xr-x 1 root root 130844393 May 23  2016 E28d20_0HGK030HF2015COG.ecw
-rwxr-xr-x 1 root root     15099 May 23  2016 E28d30_0HGK030HF2015COG.aux
-rwxr-xr-x 1 root root 244966770 May 23  2016 E28d30_0HGK030HF2015COG.ecw
-rwxr-xr-x 1 root root     15099 May 23  2016 E28d40_0HGK030HF2015COG.aux
-rwxr-xr-x 1 root root 208044160 May 23  2016 E28d40_0HGK030HF2015COG.ecw
-rwxr-xr-x 1 root root     15099 May 23  2016 E29a30_0HGK030HF2015COG.aux
-rwxr-xr-x 1 root root 216910411 May 23  2016 E29a30_0HGK030HF2015COG.ecw
-rwxr-xr-x 1 root root     15099 May 23  2016 E29a40_0HGK030HF2015COG.aux
-rwxr-xr-x 1 root root 176545547 May 23  2016 E29a40_0HGK030HF2015COG.ecw
--More--
```

Bu çıktının en altında görülen`--More--`kısmı aslında,`less`programının getirdiği bir sonuç. Aynı şekilde`less`çalıştırıldıktan sonra, standart girdiden (klavyeden) herhangi bir *input* beklemektedir. Kısacası`less`programı devreye girdikten sonra eğer bir tuşa basarsak,`ls -l`çıktısının geri kalanının ekranımıza sığdığı kadarını karşımızda görebiliriz.

Aslında buradaki notasyon şu şekilde işler.`komut1 | komut2 | komut3`şeklinde *-neredeyse- sonsuza kadar* komutları birbirine bağlayabilirsiniz ("Neredeyse sonsuza kadar" olmasının sebebini **File Descriptor** bölümünde göreceğiz). Buradaki komutlar birbirinden farklı olabileceği gibi, birbirleriyle aynı da olabilir. Bu komutların birbirleriyle *konuşabilmeleri* için bilmeleri gereken bir şey de yoktur. McIlroy'un 2. maddede bahsettiği, farklı programların birbirleriyle konuşmasını sağlama düşüncesi de burada ortaya çıkar.

Örneğin, sistemimizdeki yüklü Python modüllerinin bulunduğu`/usr/local/lib/python3.5/dist-packages`dizini içerisinde sonu`.py`ile bitmeyen dosyaların sayısını öğrenmek istersek, aşağıdaki komut dizisini kullanabiliriz.

```
eaydin@eaydin-vt ~ $ ls /usr/local/lib/python3.5/dist-packages | grep -v .py$ | wc -l
129
```

Buradaki ilk komut,`ls /usr/local/lib/python3.5/dist-packages`çok tanıdık bir iş yapıyor: dizinin içeriğini listeliyor. Ancak içeriğini standart çıktıda göstermek yerine,`grep`programına iletiyor.`grep`ise standart girdiden okuduğu veriler üzerinde`-v .py$`parametrelerini çalıştırıyor. Burada yaptığı iş, "sonu`.py`ile biten dosyaları göstermemek". Detaylarına grep ve Regular Expressions bölümünde değineceğiz. Elimizde artık sonu`.py`ile bitmeyen dosyaların bir listesi var, ancak bunu görüntelemek istemiyoruz, çünkü bunların sayısını öğrenmek istiyoruz. Öyleyse standart çıktısını`wc`(*word count*) programına iletiyoruz.`wc -l`ile standart girdiden gelen verinin kaç satır olduğunu sayıyoruz, ve bu sonucu artık standart çıktıya yazıyoruz. Bu yüzden standart çıktı olarak **129** değerini görüyoruz.

Tahmin edeceğiniz gibi, burada elde ettiğimiz sayıyı standart çıktı yerine aşağıdaki gibi bir dosyaya da yönlendirebilirdik.

```
eaydin@eaydin-vt ~ $ ls /usr/local/lib/python3.5/dist-packages | grep -v .py$ | wc -l > paket_sayisi
```

## T-Pipe

Yaptığımız son örnekte, dosyaların sayısını`paket_sayisi`isminde bir dosyaya yazdırdık. Ancak eğer bu dosya sayısını ekranda görmek istiyor, ancak dosyaların bir listesini bir dosyaya yazdırmak istiyor olsaydık?

Örneğin, eğer paketlerin listesini bir dosyaya yazdırmak isteseydik, sondaki word count komutunu kullanmayıp, grep'in standart çıktısını bir dosyaya yönlendirmemiz gerekecekti.

```
eaydin@eaydin-vt ~ $ ls /usr/local/lib/python3.5/dist-packages | grep -v .py$ > paket_listesi
```

Öte yandan, paketlerin sayısını ekranda görmek için, daha önce kullandığımız komutu kullanmamız gerekirdi.

```
eaydin@eaydin-vt ~ $ ls /usr/local/lib/python3.5/dist-packages | grep -v .py$ | wc -l
129
```

Bir akış içerisinde standart çıktıyı yönlendirmek yerine, birkaç parçaya bölme işini yapmak için`tee`isimli program geliştirilmiştir. Örneğin`tee`kullanarak aşağıdaki komut dizisini yazarsak, yukarıdaki iki komutu ayrı ayrı çalıştırmamıza gerek kalmaz.

```
eaydin@eaydin-vt ~ $ ls /usr/local/lib/python3.5/dist-packages | grep -v .py$ | tee paket_listesi | wc -l
129
```

Gördüğünüz gibi, standart çıktıya yine word count programının sonucu olan **129** yazıldı. Ancak arada`tee`programı,`grep`'in çıktısını`paket_listesi`dosyasına yazdı. Dosyanın baş kısmına`head`programıyla bakıp içeriğine göz atabiliriz.

```
eaydin@eaydin-vt ~ $ head paket_listesi 
alabaster
alabaster-0.7.10.dist-info
asn1crypto
asn1crypto-0.24.0.dist-info
attr
attrs-17.3.0.dist-info
babel
Babel-2.5.1.dist-info
bcrypt
bcrypt-3.1.4.dist-info
```

`tee`programı, aslında UNIX pipeline'ında bir T-Pipe görevi gördüğü için bu ismi almıştır. UNIX pipeline'ı aslında bir boru tesisatı gibi düşünülebilir, ismi de buradan gelir zaten. Yazılımlar birbirlerine borularla bağlıdır, ve akış tek yönlüdür. Soldan sağa doğru akış gerçekleşir. Eğer bu akış içerisinde bir dallanmaya ihtiyaç duyarsak, boru tesisatlarında olduğu gibi T şeklinde bir boru kullanmamız gerekir. Böylece akışı iki veya daha fazla dala ayırabiliriz. Programa birden fazla parametre verip, çıktının birden fazla dosyaya da yazdırılmasını sağlayabiliriz.

Kısacası`tee`programı, standart girdiden gelen veriyi, hem kendisine parametre olarak verilen dosyalara yazar, hem de standart çıktıya yönlendirir. Böylece kendi standart çıktısı hangi programa standart girdi olarak sunulmuşsa, komutların akışı devam edebilir.

Normal şartlar altında **>** işaretinin yaptığı gibi, kendisine parametre olarak verilen dosyaları silip üzerine yazar. Ancak bu dosyaların mevcut bilgilerini koruyup sonuna veri eklemesini istersek (*append* etmesini istersek)`-a`parametresiyle çalıştırmak gerekir. Bu, standart çıktı yönlendirmedeki **>>** işaretinin karşılığı gibi düşünülebilir.

### tee Örneği

Kullanımı hakkında, GNU Core Utils'de paylaşılan birkaç örnek fikir verebilir.

Örneğin herhangi bir dosyanın internetten indirilmesi ile dosyanın MD5 Checksum hesaplanmasının sağlanmasını bir arada yapmak için aşağıdaki komut incelenebilir.

```
wget -O - http://mirror.veriteknik.net.tr/CentOS/7/isos/x86_64/CentOS-7-x86_64-Minimal-1708.iso | tee centos7.iso | md5sum > centos7.md5
```

Yukarıdaki komut VeriTeknik mirrorlarından CentOS 7 Minimal güncel versiyonunu indirir,`tee`ile dosya`centos7.iso`olarak kaydedilir ancak standart çıktıya yazılan veri`tee`ile`md5sum`programına aktarılır ve MD5 Checksum hesaplandıktan sonra`centos7.md5`dosyasına kaydedilir. Burada önemli olan noktalardan birisi, MD5 hesaplanması için verinin tamamının indirilmesinin beklenmemesidir. Veri indikçe `md5sum` programına veri akacak ve hesaplama başlayacaktır. Dolayısıyla verinin önce diske yazılması beklenmemektedir. Verinin önce diske yazılmasını, sonra`md5sum`programının diskten tekrar okumasını sağlamak için şöyle yapabilirdik:

```
wget http://mirror.veriteknik.net.tr/CentOS/7/isos/x86_64/CentOS-7-x86_64-Minimal-1708.iso centos7.iso && md5sum centos7.iso
```

Ancak burada işlemler sırayla yapılacağı için, UNIX Pipeline'ın avantajlarından hiçbir şekilde faydalanmamış olurduk.

### Process Substitution

Eğer yukarıda indirdiğimiz dosyanın, indirilirken, aynı anda hem MD5 Checksum'ının, hem de SHA1 Checksum'ının hesaplanmasını isteseydik,`tee`ile standart çıktıyı iki farklı programa yönlendirmemiz gerekecekti. Bu işleme *process substitution* denilir. Aşağıdaki örnek ile görülebilir.

```
eaydin@eaydin-vt ~/Downloads $ wget -O - http://mirror.veriteknik.net.tr/CentOS/7/isos/x86_64/CentOS-7-x86_64-Minimal-1708.iso | tee 
>(sha1sum > centos7.sha1) 
>(md5sum > centos7.md5) > centos7.iso
--2018-03-14 14:19:36--
http://mirror.veriteknik.net.tr/CentOS/7/isos/x86_64/CentOS-7-x86_64-Minimal-1708.iso
Resolving mirror.veriteknik.net.tr (mirror.veriteknik.net.tr)... 94.103.33.100, 2a00:7300:1::101
Connecting to mirror.veriteknik.net.tr (mirror.veriteknik.net.tr)|94.103.33.100|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 830472192 (792M) [application/octet-stream]
Saving to: ‘STDOUT’


- 100%[=============================================================>] 792,00M  11,1MB/s    in 73s     


2018-03-14 14:20:49 (10,9 MB/s) - written to stdout [830472192/830472192]


eaydin@eaydin-vt ~/Downloads $ cat centos7.md5
5848f2fd31c7acf3811ad88eaca6f4aa  -
eaydin@eaydin-vt ~/Downloads $ cat centos7.sha1 
aae20c8052a55cf179af88d9dd35f1a889cd5773  -
```

Yukarıdaki komut dizisinin kritik noktası,`tee >(sha1sum > centos7.sha1) >(md5sum > centos7.md5)`bölümüdür. Burada `tee`, standart çıktısını iki farklı işleme daha yönlendirir. Bu işlemler parantez içinde belirtilir, ve daha önce gördüğümüz **>** işareti ile bu işlemlere yönlendirme yapılır. Burada dikkat edilmesi gereken nokta, **>** işareti ile **(** arasında boşluk bulunmaması gerektiğidir. Öte yandan`sha1sum`ve`md5sum`sonrasında gelen **>** işaretleri doğrudan bu programların standart çıktılarını yönlendirme amacıyla yazıldığından, boşluk konması problem yaratmaz, zaten parantez içinde kullanılma sebepleri de budur. (Not: Günümüzde güvenlik açısından `md5sum` ve `sha1sum` yerine `sha256sum` veya daha güçlü algoritmalar tercih edilmektedir. Örnek, konsepti göstermek amacıyla bu araçları kullanmaktadır.)

Sanki`tee`programı iki farklı dosyaya yazmak yerine, iki farklı işleme standart çıktıyı yönlendirmektedir. Burada dosya (*file*) yerine işlem (*process*) koyduğumuz için, bir değişiklik (*substitution*) işlemi yapmış olduk. Bu yüzden bu yönteme *process substitution* denilir. Bu örnekte de, indirme işleminin, SHA1 hesaplamasının ve MD5 hesaplamasının birbirlerini beklemediğini, işlemin paralel gerçekleştirildiğini (verinin aynı anda birden fazla işleme akabildiğini) hatırlatmakta fayda var. Gerçek CPU paralelizmi sistemin çekirdek sayısına ve zamanlayıcısına bağlıdır, ancak bu yöntem I/O bekleme sürelerini azaltır.


# Olmazsa Olmaz: stdio.h

Herhangi bir C programı yazdıysanız, hemen hemen her zaman `stdio.h` başlık dosyasını programın başında çağırdığınızı fark etmişsinizdir. Aslında bu dosya, programın standart girdi ve standart çıktı ile etkileşimini sağlayan bileşenleri barındırır. İsmi bu yüzden *Standard Input/Output*'un kısaltmasıdır.

Brian Kernighan ve Dennis Ritchie'nin meşhur **The C Programming Language** kitabındaki basit bir örneği uygulayacak olursak, tanıdık sonuçlar elde ettiğimizi görebilirsiniz.

```
#include <stdio.h>
#include <ctype.h>

main()
{
    int c;
    while ((c = getchar()) != EOF)
        putchar(tolower(c));
    return 0;
}
```

Yukarıdaki kodu derlediğimizde, standart girdiden okuduğu kelimelerin, küçük harfe çevrilerek standart çıktıya yazdığı görülebilir. Derlediğimiz programa `lower` ismini verecek olursak, örneğin aşağıdaki şekilde kullanabiliriz.

```
eaydin@eaydin-vt ~/devel/lower $ echo AbCdE | ./lower
abcde
```

Gördüğünüz gibi, pipe işareti ile doğrudan standart girdiden gelen veriyi okuyabildik. Eğer bu verileri bir metin dosyasına yazsaydık, standart girdi olarak metin dosyasından da yönlendirebilirdik.

Önce metin dosyamızı oluşturalım.

```
eaydin@eaydin-vt ~/devel/lower $ echo AbCdE > karakterler
eaydin@eaydin-vt ~/devel/lower $ cat karakterler 
AbCdE
```

Şimdi programımıza standart girdi olarak sunalım.

```
eaydin@eaydin-vt ~/devel/lower $ ./lower < karakterler
abcde
```

Kısacası programımız için bilginin pipe ile veya **<** işareti ile gelmesinin bir önemi yok. İkisi de standart girdi çünkü. Benzer şekilde `ls` çıktısını da programımıza yönlendirebilirdik.

```
eaydin@eaydin-vt ~/devel/lower $ ls
Buyuk_HARFLI_diZin  karakterler  lower  lower.c
eaydin@eaydin-vt ~/devel/lower $ ls | ./lower
buyuk_harfli_dizin
karakterler
lower
lower.c
```

Halbuki bölümün başında McIlroy'un belirttiği gibi, ne `ls` programının bizim `lower` programımızdan haberi var, ne de `lower` programı yazılırken `ls` ile ilgili bir noktayı dikkate aldık.

Programımızdaki `getchar` fonksiyonu, aslında standart girdiden veri okuyan kısımdır. `puthcar` fonksiyonu ise standart çıktıya veri yazmaktan sorumludur. Bu fonksiyonlar `stdio.h` ile sağlanır. Bu yüzden kullanmak için *include* etmemiz gerekir.

Eğer programı tek başına çalıştırırsak, biraz daha anlaşılabilir durum.

```
eaydin@eaydin-vt ~/devel/lower $ ./lower 
Bu bir Cümle
bu bir cümle
^C
```

Tanıdık geldi mi? Bu bölümün başlarında `cat` programını tek başına çalıştırdığımızda da benzer manzarayla karşılaşmıştık. Yine standart girdiden veri bekledi. Biz `Bu bir Cümle` yazdıktan sonra, kendisi yine standart çıktıya verinin aynısını yazdı, tıpkı `cat` gibi. Ama bu sefer karakterleri küçülttü. Yine Ctrl+c ile programımızı sonlandırarak çıktık.

Burada dikkat edilmesi gereken bir diğer nokta, programımızın parametrik şekilde girdi almaması. Örneğin karakterler dosyasını argüman olarak kendisine veremezdik, çünkü programımızda gelen argümanlarla neler yapılması gerektiğini belirtmedik. Böyle olunca argümanları görmezden gelecektir, ve yukarıdaki durumun aynısı gerçekleşecektir.

```
eaydin@eaydin-vt ~/devel/lower $ ./lower karakterler 
Argümanları Dikkate ALMADI
argümanları dikkate almadi
^C
```


# Standart Hata ve File Descriptor

## Standart Hata ve File Descriptor

Şimdiye kadar standart girdi ve çıktı yönlendirmelerini, UNIX pipeline dahilinde programların birbirleriyle iletişim sağlayabilmesi için nasıl kullandığımızı gördük.

Aslında UNIX üzerinde programların üç temel veri akış biçimi vardır. Standart girdi, standart çıktı ve standart hata. İngilizceleri *Standard Input*, *Standard Output* ve *Standard Error* olarak geçer. Bu yüzden bazen kısaltmalarını *stdin*, *stdout*, *stderr* olarak görebilirsiniz.

Standart girdi ve standart çıktının varoluş amaçlarını biraz önceki örnelerde irdeledik. Standart hata ise, program çalıştırıldığında, programın hatalarını yönlendireceği noktayı belirtir. Normal şartlar altında bir program sonuçlarını da (standart çıktı) hatalarını da (standart hata) ekranımıza yönlendirir. Böylece program hata verdiyse, çıktıları arasında görürüz. Ancak bu her zaman istediğimiz bir şey olmayabilir. Özellikle çok fazla çıktı veren programlarda gerçekleşen hataların ayıklanması zorlaşabilir. Ayrıca, programların standart çıktılarını başka program veya dosyalara yönlendirdiğimizde, hataların da burada yer almasını istemeyebiliriz. Bu tip durumların önüne geçebilmek için, standart çıktıdan bağımsız olan bir çıktı biçimi olarak standart hata tanımlanmıştır. Bu sayede örneğin bir programın standart çıktısı pipe ile bir başka programa girdi olarak sunulurken, programın çalışması sırasında oluşacak hatalar kullanıcının terminal ekranında görülebilir.

Standart hata kavramı, UNIX'in 6. versiyonunun ardından Dennis Ritchie tarafından geliştirilmiştir. Bu yöntem ile birbirine standart girdi-çıktı yönlendiren programların standart hatalarının terminale yazdırılması durumunda, hangi hata mesajının hangi programdan geldiğinin bilinmemesi problemiyle de karşılaşılmıştır. Douglas McIlroy, bu problemin farkında olduklarını ama asla tamamen çözülmediğini, *UNIX Programmer's Manual*'ın 3. versiyonunda belirtir.

> All programs placed diagnostics on the standard output. This had always caused trouble when the output was redirected into a file, but became intolerable when the output was sent to an unsuspecting process. Nevertheless, unwilling to violate the simplicity of the standard-input-standard-output model, people tolerated this state of affairs through v6. Shortly thereafter Dennis Ritchie cut the Gordian knot by introducing the standard error file. That was not quite enough. With pipelines diagnostics could come from any of several programs running simultaneously. Diagnostics needed to identify themselves. Thus began a never quite finished pacification campaign: a few recalcitrant diagnostics still remain anonymous or appear on the standard output.

Standart hata'nın kullanımı için önce, *file descriptor* konsepti hakkında kısaca fikir sahibi olmamızda fayda var.

## File Descriptor

UNIX üzerinde aslında her şey bir dosyadır. Klavyeniz, seri port cihazınız, ethernet cihazınız, yazıcınız, metin dosyanız, ekranınız... Tamamını UNIX dosya sistemi birer dosya olarak tanımlar. Programlarınız bu dosyalara erişmek istediklerinde, işletim sistemi tarafından erişim izniniz olup olmadığı kontrol edilir, ardından sistem programa "negatif olmayan bir tam sayı" olarak dosyayı sunar. Kısacası program, aslında dosyanın ismiyle, yoluyla neredeyse hiç ilgilenmez, programın etkileşim kurduğu "şey" bir tam sayıdır, bu tam sayı da işletim sistemi tarafından dosya yoluna tercüme edilir. Bu tam sayılar, program ile işletim sistemi arasındaki dosya tanımını yaptığı için, *file descriptor* ismini alır. Erişilmiş bir dosya hakkındaki bütün bilgi işletim sisteminin sorumluluğundadır, yazılımlar bu dosyaları sadece birer file descriptor olarak tanırlar. Standart girdi, standart çıktı ve standart hata, ayrı file descriptor'lar ile temsil edilir.

Daha önce incelediğimiz `stdio.h` için bu gösterimler stdin, stdout, stderr iken, bunlara karşılık gelen tam sayılar da genellikle bash gibi kabuklarda kullanılır.

| İsim           | Sayısal Değer | \<stdio.h> Kullanımı |
| -------------- | ------------- | -------------------- |
| Standart Girdi | 0             | stdin                |
| Standart Çıktı | 1             | stdout               |
| Standart Hata  | 2             | stderr               |

Daha önce gördüğümüz **<** ve **>** gösterimleri de aslında bunu doğrular niteliktedir. Programlar girdinin nereden geldiğini ve çıktının nereye gideceğini bilmezler, onlar için sadece 0, 1 ve 2 (veya stdin, stdout ve stderr) vardır. Kabuk aracılığıyla **<** ve **>** gösterimlerini kullanarak aslında işletim sistemi hangi programın nereden veri alıp nereye ileteceğini kontrol eder.

Yukarıdaki tablodan görüleceği gibi, aslında standart çıktının file descriptor'ının sayısal karşılığı 1'dir. Yani, aşağıdaki iki örnek, aynı anlama gelmektedir. İlk başta, daha önce uyguladığımız örneklerde olduğu gibi, file descriptor kullanmadan oluşan sonuca bakalım.

```bash
eaydin@eaydin-vt ~/devel/lower $ cat karakterler > cikti1
eaydin@eaydin-vt ~/devel/lower $ cat cikti1 
AbCdE
```

Aşağıda ise, file descriptor ile aynı sonucun elde edildiğini görebiliyoruz.

```bash
eaydin@eaydin-vt ~/devel/lower $ cat karakterler 1> cikti2
eaydin@eaydin-vt ~/devel/lower $ cat cikti2
AbCdE
```

Yönlendirmelerde standart çıktı çok sık kullanıldığı için, `1>` kullanımı olmadan da standart çıktı yönlendirmesi gerçekleştirilir.

Şimdi benzer işlemi standart hata yönlendirmesinde kullanalım.

cat programı, kendisine parametre olarak kaç dosya verilirse, tamamını peş peşe eklemekle görevlidir, ismi de zaten buradan gelir, *con**cat**enate* sözcüğünün kısaltılmışıdır. Aşağıdaki kullanım açıklayıcı olacaktır.

```bash
eaydin@eaydin-vt ~/devel/lower $ echo Bu bir cümle > cumleler
eaydin@eaydin-vt ~/devel/lower $ cat cumleler 
Bu bir cümle
eaydin@eaydin-vt ~/devel/lower $ cat karakterler cumleler 
AbCdE
Bu bir cümle
```

Eğer parametre olarak verdiğimiz dosyalardan birisi yoksa (veya okunamıyorsa), hata verir.

```bash
eaydin@eaydin-vt ~/devel/lower $ cat paragraf
cat: paragraf: No such file or directory
```

Aşağıda, iki dosyayı birleştirmesini istiyoruz.

```bash
eaydin@eaydin-vt ~/devel/lower $ cat karakterler paragraf > deneme
cat: paragraf: No such file or directory
eaydin@eaydin-vt ~/devel/lower $ cat deneme
AbCdE
```

Ancak gördüğünüz gibi, dosyalardan birisi (`paragraf`) olmadığı için program hata verdi. Yine de `deneme` dosyası oluşturuldu ve içinde sadece `karakterler` dosyasının içeriği yer alıyor. Eğer çok fazla dosyayı birleştiriyor olsaydık, veya bu işlemi bir script'in içerisinde kullanıyor olsaydık, veya pipe ile birçok işlemi birleştiriyor olsaydık, bu işlemin hatalarını terminal ekranına yazdırmak yerine bir dosyaya yönlendirmesini tercih edebilirdik. Bunun için file descriptor kullanımı gerekir ve yukarıdaki tablodan anlaşılacağı gibi `2>` notasyonuyla bu işlem gerçekleştirilir.

```bash
eaydin@eaydin-vt ~/devel/lower $ cat karakterler paragraf > deneme 2> hatalar
eaydin@eaydin-vt ~/devel/lower $ cat deneme 
AbCdE
eaydin@eaydin-vt ~/devel/lower $ cat hatalar
cat: paragraf: No such file or directory
```

Burada önce standart çıktıyı `deneme` dosyasına yönlendirdiğimizi, standart hatayı ise `hatalar` dosyasına yönlendirdiğimizi görebilirsiniz. Yaptığımız işlemin sırasının bir önemi yok. Yani önce standart hatayı yönlendirip, sonra standart çıktıyı yönlendirebilirdik. Genellikle bu yapılmaz (1 ve 2 sırasını içgüdüsel olarak koruruz) ancak yapılmasında bir mahsur bulunmaz.

```bash
eaydin@eaydin-vt ~/devel/lower $ cat karakterler paragraf 2> hatalar > deneme
eaydin@eaydin-vt ~/devel/lower $ cat hatalar
cat: paragraf: No such file or directory
eaydin@eaydin-vt ~/devel/lower $ cat deneme
AbCdE
```

Bütün bu işlemlerde, standart çıktı yönlendirmesi için **1>** notasyonunu da kullanabilirdik. Yine, alışkanlık gereği pek kullanılmaz sadece. Yani aşağıdaki işlem ile yukarıdaki aynı işe yarayacaktır.

```bash
eaydin@eaydin-vt ~/devel/lower $ cat karakterler paragraf 2> hatalar 1> deneme
```

### Open File Descriptor Limiti

File descriptor'ların UNIX sistemimiz üzerinde aslında çekirdek (kernel) tarafından idare edildiğini öğrendik. Yani bir program standart çıktısının nereye yazıldığını kendisi bilmiyor, ancak işletim sistemi her programın standart çıktısının (ve standart girdisinin ve standart hatasının) nereye işaret ettiğini, dolayısıyla her programın file descriptor'larının nereye karşılık geldiğini biliyor. Bu durum UNIX çekirdeğinin pek çok program için pek çok dosya işaretini *aklında tutmasına* sebep olur. Buradaki "aklında tutması" aslında sistemin bunu *RAM'de tutması* anlamına gelir. Bu yüzden sistemde file descriptor'ların bir limiti bulunur. Buna "o anda sistemin aklında tuttuğu file descriptor'lar" anlamına gelen **open file descriptor limit** denilir.

Daha önce `komut1 | komut2 | komut3` şeklinde bir pipeline oluştururken aslında *-neredeyse sonsuza kadar-* bu diziyi uzatabileceğinizi söylemiştik. Buradaki "neredeyse" kısmı da bu limitten kaynaklanır. Aslında sisteminizin open file descriptor limiti kadar uzun bir dizi oluşturabilirsiniz, çünkü buradaki her program için farklı file descriptor'lar tanımlanmaktadır. İşletim sistemi bunların ne kadarını aynı anda aklında tutabilirse, o kadar komutu pipeline içerisinde kullanabilirsiniz demektir. Yine de bu limit, sunucular üzerinde pratik kullanımlarda fark etmeyeceğiniz kadar yüksektir. Genellikle gömülü sistemlerde (kaynakların ekonomik sebeplerle düşük tutulduğu sistemlerde) problem teşkil etmeye başlar.

Sisteminiz üzerinde bu limitler farklı biçimlerde temsil edilir. İşletim sisteminizin tamamının open file descriptor limitini öğrenmek için `/proc/sys/fs/file-max` dosyasının içeriğine bakmanız yeterli olacaktır. Örneğin:

```bash
[root@emre ~]# cat /proc/sys/fs/file-max
386774
```

Burada incelediğimiz sistemin *aynı anda* 386774 tane file descriptor'ın açık olmasını desteklediğini görüyoruz. Yani UNIX pipeline'ında peş peşe çalıştırdığımız komutlar maksimum bu sayıya ulaşacak kadar file descriptor oluşturabilirler, ve tabii bu sırada çalışan programları da (network servislerinin sağlanması, init programı, varsa çalışan veritabanları, başka yazılımlar vb.) göz önünde bulundurmak gerekir. Hiç pipeline oluşturmasak bile, aslında çalışan programların da toplam bu kadar file descriptor oluşturabileceği anlamına gelir.

Ancak bu durum, tek bir programın (veya kullanıcının) 386774 limitinin çok çok büyük bir kısmını, örneğin 386000 tanesini işgal etmesine sebep olabilir. Bu tip durumların önüne geçmek için modern işletim sistemlerinde program başına open file descriptor limiti bulunmaktadır. Bunu öğrenmek için aşağıdaki komutu çalıştırabilirsiniz:

```bash
[root@emre ~]# ulimit -n
1024
```

Buradan görüleceği üzere, aslında bir program çalıştırıldığında, kendisine işletim sisteminin çekirdeği tarafından 1024 tane file descriptor oluşturma hakkı tanınır.

*"Ama önceki bölümlerde programların stdin, stdout ve stderr şeklinde 3 tane file descriptor'ı olduğunu söylemiştik? Tek program neden 1024 tane file descriptor'a ihtiyaç duysun ki?"*

Doğru, ve bu sorunun cevabını ilerleyen bölümlerde, file descriptor'ların doğasını daha derinlemesine irdelediğimizde alacağız. Şimdilik bu soruyu bir kenara bırakalım.

Sistemimizdeki open file descriptor limiti, program başına olsun veya olmasın, işletim sistemimizin limitlerine ve RAM'ine bağlı olduğu için, hali hazırda çekirdeğin aklında tuttuğu file descriptor sayısını görmek isteyebiliriz. Bunun için aşağıdaki komutu çalıştırabiliriz:

```bash
[root@emre ~]# cat /proc/sys/fs/file-nr
736    0    386774
```

Bu dosyadaki üç değerin anlamı (modern Linux çekirdeklerinde):

1. **Allocated FDs (736):** Çekirdek tarafından ayrılmış (allocate edilmiş) toplam file descriptor sayısı. Bu, o anda kullanılanları içerir.
2. **Unused Allocated FDs (0):** Ayrılmış ancak kullanılmayan file descriptor sayısı (bu değer modern çekirdeklerde genellikle 0'dır ve pek kullanılmaz).
3. **System-wide Max FDs (386774):** Sistem genelindeki maksimum open file descriptor limiti (`/proc/sys/fs/file-max` ile aynı değer).

İlk değer (allocated FDs), sistemdeki mevcut FD kullanımını gösterir. Üçüncü değer ise sistemin izin verdiği toplam üst limittir.

Bu limitlerin nasıl düzenleneceğini, program başına neden limitler olduğunu biraz daha ilerleyen bölümlerde irdeleyeceğiz. Şimdi programların üç temel file descriptor'ına geri dönelim.

### Standart Hatanın Standart Çıktıya Yönlendirilmesi

Her ne kadar standart hata yönlendirmesi, standart çıktı ile aynı noktaya yazılmasını istemediğimizden dolayı ortaya çıkmış olsa da, bazı durumlarda hata ve çıktıyı aynı yere yazmak isteyebiliriz. Bu gibi durumlar için, file descriptor kullanımında farklı bir gösterim kullanılır.

```bash
eaydin@eaydin-vt ~/devel/lower $ cat karakterler paragraf > sonuc 2>&1
eaydin@eaydin-vt ~/devel/lower $ cat sonuc
AbCdE
cat: paragraf: No such file or directory
```

Yukarıdaki örnekte, yine `cat` programı ile `karakterler` ve `paragraf` dosyalarını okuyup birleştirmek istedik. Birleşmiş çıktıyı da `sonuc` isminde bir dosyaya yazmak istedik. Ancak `paragraf` diye bir dosyamız bulunmadığı için, programın hata vermesini bekleriz. Fakat programı çalıştırırken, standart hatayı da, standart çıktıya yazmasını söyledik. Standart çıktımız `sonuc` dosyası olduğu için, hatalarımızı ekranda görmek yerine, `sonuc` dosyasında görmeyi bekleriz. Gerçekten de `sonuc` dosyasının içeriğine baktığımızda hem `karakterler` dosyasının içeriğini, hem de `paragraf` dosyası bulunamadığı için `cat` programının verdiği hatayı görüyoruz.

Burada standart hatayı, standart çıktıya yönlendirmek için kullanılan notasyon biraz farklı görünebilir: `2>&1`

Bu gösterimin ne anlama geldiği, aslında yine Brian Kernighan ve Dennis Ritchie'nin The C Programming Language kitabının 8. bölümünde yatıyor:

> A file descriptor is analogous to the file pointer used by the standard library \[...]

Yani, bir *file descriptor*, aslında C programlama dilinde standart kütüphanenin kullandığı *file pointer*'lar ile aynı işi yapıyor. C'de adres gösterimi **&** işaret ile yapılmakta. Bunu, daha önce 1 olarak tanımlanmış bir değerin adresi olarak düşünebilirsiniz. Yukarıdaki bash satırında da, `cat` programının standart çıktısı için sonuc tanımlandı. Dolayısıyla 1 (stdout) değeri için bir adres belirtmiş olduk. Daha sonra 2 (stderr) değeri için adres belirtirken de "daha önce 1 için tanımladığım **adresi** kullan" demiş oluyoruz. Burada **adres** sözcüğüne karşılık gelmesi için de, C'deki pointer'ların adres gösterim gibi **&** işareti kullanılmaktadır.

Burada **&** işaretini, bir programı arka planda çalıştırmak için sonuna koyduğumuzdaki kullanımıyla karıştırmamakta fayda var. Eğer ardından 1 veya 2 geliyorsa, doğrudan file desriptor için adres görevi görmektedir.

Yukarıdaki işlemi de yine tersi olarak yapabilirdik. Yani önce standart hata yönlendirmesi yapıp, daha sonra standart çıktının yönleneceği yerin, standart hatanın adresi olmasını da söyleyebilirdik.

```bash
eaydin@eaydin-vt ~/devel/lower $ cat karakterler paragraf 2> hatalisonuc 1>&2
eaydin@eaydin-vt ~/devel/lower $ cat hatalisonuc 
AbCdE
cat: paragraf: No such file or directory
```

**Bash Shorthand (`&>`)**

Modern Bash kabuklarında (ve zsh gibi diğer bazı kabuklarda), hem standart çıktıyı (1) hem de standart hatayı (2) aynı hedefe yönlendirmek için `&>` veya `>&` kısayolu kullanılabilir. Bu, `> dosya 2>&1` ile eşdeğerdir:

```bash
# Hem stdout hem de stderr'i sonuc_hepsi dosyasına yönlendir
cat karakterler paragraf &> sonuc_hepsi 

# Yukarıdaki komut şununla aynıdır:
# cat karakterler paragraf > sonuc_hepsi 2>&1
```

### Çıktı Yönlendirme Örneği

Genellikle standart hatayı ve standart çıktıyı birlikte yönlendirme işini, kalabalık çıktı sunan bir programın arka planda çalışmasında kullanırız. Örneğin checkmate.py isimli geliştirdiğimiz bir Python programı, belirli dizinlerdeki dosyaları tarayıp içlerinde bozuk dosya olup olmadığını kontrol etmektedir. Bu programın çıktısı "dosyaları kontrol ettim, problem yok" veya "dosyaları kontrol ettim, problem var" şeklinde olabilir. Kontrol işlemini bitirince email ile uyarı göndermektedir. Bu programın oluşabilecek hatası ise, kontrol edeceği dizinlere erişememesi durumunda gerçekleşebilir. Öyleyse aşağıdaki gibi programı çalıştırırsak:

```bash
root@ubuntu:~# ./checkmate.py >> /var/log/checkmate.log 2>&1
```

Program çalışmaya başlayacak, ancak hem "kontrol ettim problem var/problem yok" gibi uyarılarını, hem de programın akışında yaşayacağı problemleri aynı dosyaya, `/var/log/checkmate.log` dosyasına yönlendirecektir. Ayrıca bu dosyada mevcut log satırlarını silmeyecektir, çünkü **>>** işaretiyle satırları sonuna eklemek istediğimizi belirttik.

Terminalimizde yeni bir işlem yapmak için, programın sonlanmasını beklememiz gerekir. Eğer bunu istemeseydik, sonuna bir **&** işareti daha eklememiz gerekecekti.

```bash
root@ubuntu:~# ./checkmate.py >> /var/log/checkmate.log 2>&1 &
```

Buradaki iki **&** işaretinin farklı görevler gördüğünün daha önce altını çizmiştik. `2>&1` gösterimindeki **&** işaret, standart hatanın, standart çıktının adresine yönlenmesini sağlamaktadır. Ardından gelen **&** işareti ise bütün işlemin arka planda yürütülmesini söyler.

Bazı durumlarda programlar arka planda çalışırken, standart hataları doğru yere yönlendirilmez. Aşağıdaki gibi bir kullanım buna karşılık gelir:

```bash
root@ubuntu:~# ./checkmate.py >> /var/log/checkmate.log &
```

Bu durumda, `checkmate.py` programı arka planda işini yapacak ve "kontrol ettim hata var/yok" bilgilerini yine doğru log dosyasına yazacaktır. Bu işlemler gerçekleştirilirken biz de aynı terminal ekranında başka işlerimize devam edebilir oluruz. Ancak eğer bu sırada `checkmate.py` programı bir hatayla karşılaşırsa, bunu terminal ekranına yazdıracaktır. Bazen terminal üzerinde çalışırken durduk yere bu tip mesajlarla karşılaşabilirsiniz. Bu durumlar çoğunlukla arka planda çalışan bir işlemin standart hatasının doğru yönlendirilmemesinden kaynaklanır.

Genellikle standart çıktıyı ve standart hatayı aynı yere yönlendirme işlemini `/dev/null` dosyası ile görebilirsiniz. İleride göreceğimiz özel dosyalardan birisi olan `/dev/null`, içine yazılan her şeyi silen özel bir dosyadır. Böylece, örneğin `checkmate.py` programımızın çalışmasını istiyorsak, ancak oluşturacağı çıktılarla hiç ilgilenmiyorsak, bütün çıktılarını `/dev/null` dosyasına yönlendirip, bu çıktıların sistemde tutulmamasını sağlayabiliriz.

```bash
root@ubuntu:~# ./checkmate.py > /dev/null 2>&1 
# veya kısayolu ile:
# ./checkmate.py &> /dev/null
```

Bu tip kullanıma, en çok (yine ileride göreceğimiz) zamanlanmış görevlerde rastlarız. `crontab` içine yazılan satırların çoğu, eğer loglanmasını istemediğimiz işlemler yapıyorsa bu şekilde yazılır.

## Programların File Descriptor'ları

Aşağıdaki C kodunun derlendiği bir programı düşünelim.

```c
#include <stdio.h>
#include <unistd.h>

int main() {
    while (1) {
        printf("Test\n");
        sleep(1);
    }
    return 0;
}
```

Eğer bu programı `deneme.c` olarak kaydedip aşağıdaki şekilde derler ve çalıştırırsak, her saniye ekrana `Test` yazmasını bekleriz.

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ gcc deneme.c -o deneme
eaydin@eaydin-vt ~/devel/sleep-test $ ./deneme
Test
Test
Test
Test
```

Yani aslında program standart çıktıya `Test` yazıyor. Şimdi bu programın Linux üzerindeki process ID'sini (PID) öğrenelim. (Bunu program çalışırken yapıyoruz)

```bash
eaydin@eaydin-vt ~ $ ps ax | grep deneme
18622 pts/1    S+     0:00 ./deneme
18650 pts/2    S+     0:00 grep --color=auto deneme
```

Programın sistem üzerindeki PID'si 18622'ymiş. İşletim sisteminin çekirdeği tarafından bu işlemciye ayrılan file descriptorları, `/proc` dizini altında görebiliriz (Yine, program hala çalışıyorken yapıyoruz bu işlemleri).

```bash
eaydin@eaydin-vt ~ $ ls /proc/18622/fd/
0  1  2
```

Buradaki notasyona ve sonuçlarına dikkat edecek olursak, `/proc` isminde özel bir dizine baktık. Bu dizin Linux çekirdeğiyle ilgili işlemleri tutuyor. Bunun altında hangi PID'li işleme bakacaksak, onun için açılan dizine girdik. Onun içinde de File Descriptor'ın kısaltmasını temsil eden `fd` dizinine baktık. Burada 3 tane file descriptor ile karşılaştık: her program çalıştırıldığında işletim sistemi çekirdeğinin öntanımlı olarak atadığı standart file descriptorlar. Aslında burada gördüğümüz üç dosya, birer sembolik link, daha detaylı bakacak olursak:

```bash
eaydin@eaydin-vt ~ $ ls -l /proc/18622/fd/
total 0
lrwx------ 1 eaydin eaydin 64 Mar 22 14:36 0 -> /dev/pts/1
lrwx------ 1 eaydin eaydin 64 Mar 22 14:36 1 -> /dev/pts/1
lrwx------ 1 eaydin eaydin 64 Mar 22 14:34 2 -> /dev/pts/1
```

Buradan görüleceği üzere, aslında programın standart girdisi, standart çıktısı, standart hatası aynı noktaya işaret ediyor, `/dev/pts/1` yani terminal ekranımıza.

Şimdi programımızı durdurup, tekrar çalıştırırken standart çıktısını bir dosyaya yönlendirelim.

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ ./deneme > cikti
```

Yeni PID'yi öğrenip, file descriptorlarına baktığımızda durum aşağıdaki gibi oluyor:

```bash
eaydin@eaydin-vt ~ $ ps ax | grep deneme
18895 pts/1    S+     0:00 ./deneme
18899 pts/2    S+     0:00 grep --color=auto deneme
eaydin@eaydin-vt ~ $ ls -l /proc/18895/fd
total 0
lrwx------ 1 eaydin eaydin 64 Mar 22 14:41 0 -> /dev/pts/1
l-wx------ 1 eaydin eaydin 64 Mar 22 14:41 1 -> /home/eaydin/devel/sleep-test/cikti
lrwx------ 1 eaydin eaydin 64 Mar 22 14:40 2 -> /dev/pts/1
```

Standart girdi hala terminal ekranı, standart hata da öyle, ancak standart çıktıyı yönlendirdiğimiz dosyayı burada görebiliyoruz. Öyleyse sistem üzerinde çalışan programların hangi dosyalara eriştiğini, dolayısıyla açık file descriptor'larını bu şekilde öğrenebiliyoruz.

## Standart Olmayan File Descriptor'lar

Bu bölüm boyunca, programların üç tane file descriptor'ından bahsettik. Standart girdi, standart çıktı, standart hata. Aslında Dennis Ritchie standart hata'yı UNIX'in 6. versiyonu üzerinde tanımladığında tam olarak şunu yaptı: bir program çalışmaya başladığında, programın *ön tanımlı* 3 tane file descriptor'ı olsun. Bu yüzden bunlara *standart* diyoruz aslında. Çünkü programlar -neredeyse- her zaman bu üç tip file descriptor'a ihtiyaç duyuyorlar. Ancak bir programın 3'ten fazla file descriptor'ı olabilir.

Daha önce herhangi bir C programının `getchar` veya `putchar` gibi fonksiyonlar ile standart girdi ve standart çıktıyı kontrol ettiğini gördük. Ancak C programı bu işleri yaparken, bir yandan bir dosyayı açıp üzerinde işlem yapmasını sağlayabiliriz. Bu dosya söz konusu standart çıktı olmak zorunda değil. Örneğin biraz önce yazdığımız `deneme` programı ekrana (standart çıktıya) `Test` yazdırırken, bir yandan `yaz.txt` isimli bir dosya açıp içinde işlemler yapabilir. Aşağıdaki kodu `deneme2.c` olarak kaydedip derlersek bu durumu irdeleyebiliriz.

```c
#include <stdio.h>
#include <unistd.h>

int main() {

    FILE *fp;
    fp = fopen("yaz.txt", "w");

    while (1) {
        printf("Test\n");
        sleep(1);
    }
    return 0;
}
```

Programı derleyip yine PID'sini öğrenip file descriptor'larına bakalım:

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ ls -l /proc/22447/fd
total 0
lrwx------ 1 eaydin eaydin 64 Mar 22 15:45 0 -> /dev/pts/2
lrwx------ 1 eaydin eaydin 64 Mar 22 15:45 1 -> /dev/pts/2
lrwx------ 1 eaydin eaydin 64 Mar 22 15:45 2 -> /dev/pts/2
l-wx------ 1 eaydin eaydin 64 Mar 22 15:45 3 -> /home/eaydin/devel/sleep-test/yaz.txt
```

Burada daha önce görmediğimiz, yeni bir file descriptor açığa çıktı. Standart 0, 1 ve 2 dışında bir de 3 numaralı file descriptor. Kod içerisinde `yaz.txt` dosyasını açmasını söyledik, işletim sistemi de programın çalıştığı dizin altında `yaz.txt` diye bir dosya oluşturup bunu programın 3 numaralı file descriptor'ı ile eşleştirdi.

Eğer programımızı `yaz.txt` içerisine de satırlar yazıp kaydedecek şekilde düzenlersek, burada da bir takım sonuçlar görmeyi bekleriz. Örneğin kodumuz aşağıdaki gibi olsaydı:

```c
#include <stdio.h>
#include <unistd.h>

int main() {

    FILE *fp;
    fp = fopen("yaz.txt", "w");

    int i;

    for (i=0;i<10;i++) {
        printf("Test\n");
        fprintf(fp, "Dosyaya yazdırma\n");
        sleep(1);
    }
    fclose(fp);
    return 0;
}
```

Bu durumda ekrana (standart çıktıya) `Test` yazarken, `yaz.txt` içerisine `Dosyaya yazdırma` yazmasını beklerdik. Bunu 10 kere yapıp (her birini bir saniye arayla) sonra da program sonlanırdı. Bu durumda da yine `yaz.txt`'nin file descriptor'lar arasında 3 numaraya sahip olacağını düşünmek normal. Peki programı çalıştırırken, 3 numaralı file descriptor'ı yeni bir dosyaya yönlendirirsek? `yaz.txt` içerisine yazılacak verinin başka yere yazılmasını mı bekleriz?

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ ./deneme3 3>yeni.txt
Test
Test
Test
```

Bu durumda kodumuzun 3. çıktısını `yeni.txt`'ye yönlendiriyoruz. Hemen sistemde açık file descriptor'larına bakalım.

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ ls -l /proc/23705/fd
total 0
lrwx------ 1 eaydin eaydin 64 Mar 22 15:59 0 -> /dev/pts/2
lrwx------ 1 eaydin eaydin 64 Mar 22 15:59 1 -> /dev/pts/2
lrwx------ 1 eaydin eaydin 64 Mar 22 15:59 2 -> /dev/pts/2
l-wx------ 1 eaydin eaydin 64 Mar 22 15:59 3 -> /home/eaydin/devel/sleep-test/yeni.txt
l-wx------ 1 eaydin eaydin 64 Mar 22 15:59 4 -> /home/eaydin/devel/sleep-test/yaz.txt
```

Beklediğimiz sonucu vermedi. Sistem 3. file descriptor'ı terminalde belirttiğimiz gibi `yeni.txt` dosyasına yönlendirdi, program içerisinde açtığımız `yaz.txt` ise kendine yeni bir numara edinerek 4. file descriptor oldu.

İşletim sisteminin çekirdeği şu şekilde davranıyor: "Bu program ile ilgili bir dosya işlemi talep edildiğinde, eğer bana file descriptor adresi (numarası) verilmemişse, ben sıradan uygun ilk rakamı tahsis edeyim."

Öyleyse kodumuz içerisinde özellikle `yaz.txt` yolunu belirtmek yerine, file descriptor'a yazmasını belirtebilirdik.

```c
#include <stdio.h>
#include <unistd.h>

int main() {

    int i;

    for (i=0;i<10;i++) {
        printf("Test\n");
        write(3, "Dosyaya yazdırma\n", 18);
        sleep(1);
    }
    return 0;
}
```

Programı derleyip çalıştırdığımızda, standart çıktıya sadece Test yazdığını görüyoruz.

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ ./deneme4 3>yeni.txt
Test
Test
Test
Test
Test
Test
Test
Test
Test
Test
```

Öte yandan, 3. file descriptor'ını `yeni.txt`'ye yönlendirmiştik. Kodun içerisinde hiçbir yerde dosya ismi belirtmedik, ancak kodda 3. file descriptor'a bir yazma işlemi söz konusu. PID'den açık file descriptor'lara bakalım.

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ ls -l /proc/24419/fd
total 0
lrwx------ 1 eaydin eaydin 64 Mar 22 16:18 0 -> /dev/pts/2
lrwx------ 1 eaydin eaydin 64 Mar 22 16:18 1 -> /dev/pts/2
lrwx------ 1 eaydin eaydin 64 Mar 22 16:18 2 -> /dev/pts/2
l-wx------ 1 eaydin eaydin 64 Mar 22 16:18 3 -> /home/eaydin/devel/sleep-test/yeni.txt
```

Öyleyse yeni.txt içerisinde beklediğimiz satılar olmalı.

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ cat yeni.txt 
Dosyaya yazdırma
Dosyaya yazdırma
Dosyaya yazdırma
Dosyaya yazdırma
Dosyaya yazdırma
Dosyaya yazdırma
Dosyaya yazdırma
Dosyaya yazdırma
Dosyaya yazdırma
Dosyaya yazdırma
```

İşin ilginç tarafı, programımızı çalıştırırken 3. numaralı file descriptor'ı hiçbir yere yönlendirmeseydik, sistem üzerinde file descriptor oluşmayacaktı bile.

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ ./deneme4
Test
Test
Test
Test
Test
Test
Test
Test
Test
Test
```

Bu durumda açık file descriptor'lara bakacak olursak:

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ ls -l /proc/24890/fd
total 0
lrwx------ 1 eaydin eaydin 64 Mar 22 16:29 0 -> /dev/pts/2
lrwx------ 1 eaydin eaydin 64 Mar 22 16:29 1 -> /dev/pts/2
lrwx------ 1 eaydin eaydin 64 Mar 22 16:29 2 -> /dev/pts/2
```

Çünkü ne programın içinde, ne de programı çalıştırırken 3. file descriptor'ın nereye işaret edeceğini söylemedik.

Her ne kadar ilk üç file descriptor standart olarak belirlenmiş olsa da, programın kodlarında ilgili descriptor'ları kapatıp yeniden bir dosya açtığımızda işletim sistemi çekirdeğinin bu descriptor'ları kullandığını gözlemek mümkün. Yani 1 numaralı file descriptor'ı C kodundan kapatırsak, sonra C kodu içerisinde yeni bir dosyaya erişim sağlayacak olursak, işletim sistemi ilk uygun boş sayı 1 olacağı için bu değeri kullanacaktır.

### Alternatif File Descriptor'ın Pipeline'da Kullanımı

Programları birbirlerine pipeline ile bağlarken, eğer bir programın alternatif file descriptorlarından birini kullanmak istiyorsak biraz dolambaçlı bir yol izlemek gerekecektir. Örneğin biraz önceki `deneme4` programımızın 3. file descriptor çıktısını `grep`'e göndermek istiyorsak, ve sadece 3. file descriptor'ı ile ilgileniyorsak, programın 1. descriptor'ı ile 3. descriptor'ını yer değiştirebiliriz. Böylece programın sanki standart çıktısından bu bilgiler çıkıyormuş gibi davranır, pipe ise bunu olduğu gibi diğer programa taşır.

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ ./deneme4 3>&1 | grep Dos
Dosyaya yazdırma
Dosyaya yazdırma
Dosyaya yazdırma
^C
```

Ancak bu örnekte standart çıktıya yazılan `Test` satırlarını kaybettik. Eğer hem 3. hem de 1. descriptor'ın sonuçlarıyla ilgileniyorsak, process substitution tekniğini kullanabiliriz.

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ ./deneme4 3> >(grep Dos)
Test
Dosyaya yazdırma
Test
Dosyaya yazdırma
Test
Dosyaya yazdırma
^C
```

Burada dikkat edilmesi gereken nokta, standart çıktının verilerini `grep` programına yollamadık, dolayısıyla ekranda gördüğümüz `Test` satırları `grep`'in işlemlerinden geçmedi, sadece `Dosyaya yazdırma` satırları buradan geçti.

Eğer birden fazla file descriptor'ın birden fazla programa çeşitli yollarda gönderilmesini istiyorsak, en pratik çözüm ilerleyen bölümlerde göreceğimiz **named pipe** kullanımı olacaktır.

### Çalışan Programların File Descriptor'larına Müdahale Etmek

**(Not: Bu bölüm, çalışan işlemlere `gdb` gibi araçlarla müdahale etmeyi içerir ve ileri düzey bir konudur. Dikkatli olunmalıdır.)**

Daha önceki örneklerimizde, yazdığımız programın hangi dosyayla işlem yapacağını kodun içinde belirttiğimiz takdirde, bunları /proc dizini altından görebildiğimizi, örneğin yaz.txt dosyasına satır yazan programımızda gördük. Ancak programı çalıştırırken file descriptor yönlendirmesi ile bu dosyayı değiştiremedik, çünkü sistem yeni bir file descriptor olarak tanımladı.

GNU'yu geliştirirken Richard Stallman'ın ilk yazdığı programlardan birisi, bu bölümde de sıkça kullandığımız gcc olmuştur, yani GNU C Compiler. Yine hemen ardından gdb ismi verilen, GNU Debugger'ı geliştirmiştir. GNU Debugger sayesinde, sistemde çalışan programlara müdahale etmek mümkündür. Çalışan bir programı öldürmeden de file descriptor'larına bu araç sayesinde müdahale edilebilir.

Daha önce yazdığımız programı biraz daha şekillendirip aşağıdaki şekle sokalım.

```c
#include <stdio.h>
#include <unistd.h>
#include <time.h>

int main() {

    FILE *fp;
    fp = fopen("yaz.txt", "w");

    while (1) {
        printf("Test\n");
        time_t now;
        time(&now);
        fprintf(fp, "%s: %s", "Dosyaya yazdırma", ctime(&now));
    fflush(fp);
    sleep(1);
    }
}
```

Burada program kısaca şunu yapıyor:

* `yaz.txt` isminde bir dosya açıyor.
* Sonsuz döngüye giriyor, ve standart çıktıya `Test` yazıyor.
* Mevcut tarihi/saati öğreniyor.
* `yaz.txt` dosyasına`Dosyaya yazdırma` cümlesini ve mevcut saati aynı satırda yazıyor.
* Dosyaya söz konusu satırı yazma işlemini yapıyor. (Eğer `fflush` kullanmazsak, dosyayı kapatana kadar veriler dosyaya yazılmaz, ancak programımız sonsuza kadar çalışsın istediğimiz için bu durumu tercih etmiyoruz)
* 1 saniye uyuyup, döngüye baştan başlıyor.

Daha önce gördüğümüz gibi bu programın `yaz.txt`'ye farklı veri, standart çıktıya farklı veri yazmasını bekleriz.

Programı çalıştırınca terminale Test yazdığını görebiliriz.

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ ./deneme5
Test
Test
Test
```

Aynı anda farklı bir terminalden `yaz.txt` dosyasını takip edebiliriz, orada da beklediğimiz gibi her saniye tarih yazıyor.

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ tailf yaz.txt 
Dosyaya yazdırma: Sat Mar 24 00:34:58 2018
Dosyaya yazdırma: Sat Mar 24 00:34:59 2018
Dosyaya yazdırma: Sat Mar 24 00:35:00 2018
```

Şimdi yine farklı bir terminalde yaz2.txt isminde boş bir dosya oluşturalım, ve onu da takip edelim.

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ tailf yaz2.txt
```

Normal olarak bu dosya boş. Şimdi derlediğimiz kodun PID'sini öğrenip açık file descriptor'larına bakalım.

```bash
eaydin@eaydin-vt ~ $ ps aux|grep deneme5 
eaydin     381  0.0  0.0   4352   648 pts/11   S+   00:37   0:00 ./deneme5
eaydin     395  0.0  0.0  15628  1088 pts/15   S+   00:38   0:00 grep --color=auto deneme5
```

Programımıza işletim sistemi 381 PID'sini atamış.

```bash
eaydin@eaydin-vt ~ $ cd /proc/381/fd
eaydin@eaydin-vt /proc/381/fd $ ls -l
total 0
lrwx------ 1 eaydin eaydin 64 Mar 24 00:38 0 -> /dev/pts/11
lrwx------ 1 eaydin eaydin 64 Mar 24 00:38 1 -> /dev/pts/11
lrwx------ 1 eaydin eaydin 64 Mar 24 00:38 2 -> /dev/pts/11
l-wx------ 1 eaydin eaydin 64 Mar 24 00:38 3 -> /home/eaydin/devel/sleep-test/yaz.txt
```

3 numaralı file descriptor yaz.txt dosyasına işaret ediyor. Bunda şaşılacak bir şey yok. Bu yüzden saat bilgisini buradan okuyoruz. Şimdi gdb ile 381 PID'li işleme \_bağlanırsak, \_program üzerinde bir takım müdahalelerde bulunabiliriz. Bu işlemi root yetkisiyle yapmak gerekiyor. Doğrudan aşağıdaki gibi bir çıktı sizi karşılayacaktır.

```bash
eaydin@eaydin-vt ~/devel/sleep-test $ sudo gdb -p 381
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
Attaching to process 381
Reading symbols from /home/eaydin/devel/sleep-test/deneme5...(no debugging symbols found)...done.
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/libc-2.23.so...done.
done.
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/ld-2.23.so...done.
done.
0x00007f84c88632f0 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:84
84    ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb)
```

Bu işlemi yapar yapmaz, aslında gdb bizim işlemimizi durdurdu. Ancak kesinlikle işlemi öldürmedi, çekirdek tarafından programımız kısa süreli olarak durduruldu. Bu yüzden ne standart çıktıya Test yazmaya devam etmektedir, ne de yaz.txt içerisine mevcut saati yazmaktadır. Yine de bu dosyaları izlemeye devam edelim.

Bu noktada gdb ile programa bir dosya açma çağrısı yapacağız. Sanki program içinde dosya açan yeni bir satır kod varmış gibi davranacak.

```gdb
(gdb) call open("/home/eaydin/devel/sleep-test/yaz2.txt", 577, 0644)
$1 = 4
```

Burada open fonksiyonuna parametre olarak yeni file descriptor'ımızın nereye işaret edeceğini, yani dosya ismini, bu dosyaya erişim biçimini (577) ve bu dosyanın izinlerini (0644) belirttik. 0644 daha önce gördüğümüz izin yapısıdır. Bu örnekte 577 olarak verdiğimiz dosyaya erişim biçimi, **>** işaretine tekabül eder. Eğer **>>** şeklinde davranmasını isteseydik, 1089 değerini girmek gerekecekti. Daha net olmak gerekirse,

| gdb Dosya Erişim Biçimi | C Karşılığı                        | Terminal Yönlendirme Karşılığı |
| ----------------------- | ---------------------------------- | ------------------------------ |
| 577                     | O\_WRONLY \| O\_CREAT \| O\_TRUNC  | >                              |
| 1089                    | O\_WRONLY \| O\_CREAT \| O\_APPEND | >>                             |
| 0                       | O\_RDONLY                          | <                              |

Öyleyse, bu modda açtığımız için, eğer `yaz2.txt` dosyası içerisinde bir veri olsaydı silinmiş olacaktı.

Bu yeni dosya açma işleminin sonucunda `$1 = 4` yazması, ilk çalıştırdığımız komutun çıktısında 4 elde ettiğimiz anlamına geliyor. Burada 4 değeri, `open` fonksiyonunun sonucu olduğu için, aslında programın yeni file descriptor'ının sayısal karşılığıdır. File descriptor'ların listesinden de bu görülebilir.

```bash
eaydin@eaydin-vt /proc/381/fd $ ls -l
total 0
lrwx------ 1 eaydin eaydin 64 Mar 24 00:56 0 -> /dev/pts/11
lrwx------ 1 eaydin eaydin 64 Mar 24 00:56 1 -> /dev/pts/11
lrwx------ 1 eaydin eaydin 64 Mar 24 00:56 2 -> /dev/pts/11
l-wx------ 1 eaydin eaydin 64 Mar 24 00:56 3 -> /home/eaydin/devel/sleep-test/yaz.txt
l-wx------ 1 eaydin eaydin 64 Mar 24 00:56 4 -> /home/eaydin/devel/sleep-test/yaz2.txt
```

Hatırlarsanız bu sayısal değerler sadece 0,1,2,... gibi değerler olabiliyordu. Eğer hatalı bir işlem söz konusu olursa, gdb burada -1 değerini döndürecektir ve file descriptor'lar listesinde yeni dosyamız görülmeyecektir.

Şimdi 4 numaralı file descriptor'ın kopyasının 3 numaralı file descriptor'a yönlenmesini sağlayacağız.

```gdb
(gdb) call dup2(4,3)
$2 = 3
```

Burada C'nin `dup2` fonksiyonunu çağırmış olduk, yani 4. file descriptor'ınn bir kopyasını oluşturup 3. file descriptor'a yazdık. Aslında bu, terminal üzerinde`komut 3>&4` işlemi yapmakla aynı anlama geliyor, 3 numaralı file descriptor 4'ün adresine yönlendiriliyor. Şimdi file descriptor'larımızın listesine göz atacak olursak, 3 ve 4'ün aynı noktaya işaret ettiğini görebiliriz.

```bash
eaydin@eaydin-vt /proc/381/fd $ ls -l
total 0
lrwx------ 1 eaydin eaydin 64 Mar 24 02:28 0 -> /dev/pts/11
lrwx------ 1 eaydin eaydin 64 Mar 24 02:28 1 -> /dev/pts/11
lrwx------ 1 eaydin eaydin 64 Mar 24 02:28 2 -> /dev/pts/11
l-wx------ 1 eaydin eaydin 64 Mar 24 02:28 3 -> /home/eaydin/devel/sleep-test/yaz2.txt
l-wx------ 1 eaydin eaydin 64 Mar 24 02:28 4 -> /home/eaydin/devel/sleep-test/yaz2.txt
```

Artık, kullanmadığımız 4 numaralı file descriptor'ını kapatabiliriz.

```gdb
(gdb) call close(4)
$3 = 0
```

Bunun sonucunda, file descriptor listesinde 4 numaralı adresi görmemeyi bekleriz.

```bash
eaydin@eaydin-vt /proc/381/fd $ ls -l
total 0
lrwx------ 1 eaydin eaydin 64 Mar 24 02:28 0 -> /dev/pts/11
lrwx------ 1 eaydin eaydin 64 Mar 24 02:28 1 -> /dev/pts/11
lrwx------ 1 eaydin eaydin 64 Mar 24 02:28 2 -> /dev/pts/11
l-wx------ 1 eaydin eaydin 64 Mar 24 02:28 3 -> /home/eaydin/devel/sleep-test/yaz2.txt
```

Artık `gdb` ile bağlantı kurduğumuz PID'den kopyabiliriz.

```gdb
(gdb) detach
Detaching from program: /home/eaydin/devel/sleep-test/deneme5, process 381
```

Bunu yaptığımız anda, tekrardan programın standart çıktıya `Test` yazmaya devam ettiğini görebiliriz, Ayrıca `yaz.txt`'ye artık veri yazılmadığını, ancak takip ettiğimiz `yaz2.txt` üzerine yeni tarih/saat değerlerinin yazıldığını görebiliriz.

```
(yaz2.txt dosyasının içeriği)
Dosyaya yazdırma: Sat Mar 24 02:34:19 2018
Dosyaya yazdırma: Sat Mar 24 02:34:20 2018
Dosyaya yazdırma: Sat Mar 24 02:34:21 2018
Dosyaya yazdırma: Sat Mar 24 02:34:22 2018
Dosyaya yazdırma: Sat Mar 24 02:34:23 2018
```

`gdb`'den çıkmak için quit yazmamız yeterli.

```gdb
(gdb) quit
```

Bu yöntem ile programın 3. file descriptor'ının işaret ettiği dosyayı değiştirmiş olduk. Bu işlem sırasında programı duraklattık ancak programı öldürmedik. Yani programın PID'si değişmedi. Ayrıca program durduğundan bile haberdar olmadı. Eğer program bu sırada bir matematiksel işlem yapıyor olsaydı, durduğu için bir problem yaşamayacaktı. Bu tip işlemler özellikle `logrotate` gibi programlar tarafından kullanılır, Apache veya MySQL gibi servislerin log yazdığı dosyaların, programların hizmet kesintisine sebep olmadan değiştirilmesine olanak tanır.

## Open File Descriptor Limitine Dönüş

Daha önce işletim sisteminin aklında tuttuğu file decriptor sayısına bir limit getirdiğini, üstelik program başına da bir limit getirdiğini görmüştük. Daha önce incelediğimiz örnekte bunun bir PID başına 1024 tane olduğuyla karşılaşmıştık. Bir programın neden 3'ten fazla file descriptor'a ihtiyaç duyabileceği, alternatif file descriptor'lar ile tanıştığımızda netleşmiştir herhalde.

Örneğin bir sunucu üzerinde çalışan MySQL Veritabanı servisinin açık file descriptor'larından bir kesit aşağıda görülebilir:

```bash
[root@emre ~]# ls -l /proc/6274/fd
total 0
lr-x------ 1 root root 64 Mar 20 18:26 0 -> /dev/null
l-wx------ 1 root root 64 Mar 20 18:26 1 -> /var/log/mysqld.log
lrwx------ 1 root root 64 Mar 20 18:26 10 -> socket:[187781]
lrwx------ 1 root root 64 Mar 20 18:26 11 -> /tmp/ibnc02LB (deleted)
lrwx------ 1 root root 64 Mar 20 18:26 12 -> socket:[187782]
lrwx------ 1 root root 64 Mar 20 18:26 13 -> /var/lib/mysql/mysql/host.MYI
lrwx------ 1 root root 64 Mar 20 18:26 14 -> /var/lib/mysql/mysql/host.MYD
lrwx------ 1 root root 64 Mar 20 18:26 15 -> /var/lib/mysql/mysql/user.MYI
lrwx------ 1 root root 64 Mar 20 18:26 16 -> /var/lib/mysql/mysql/user.MYD
lrwx------ 1 root root 64 Mar 20 18:26 17 -> /var/lib/mysql/mysql/db.MYI
lrwx------ 1 root root 64 Mar 20 18:26 18 -> /var/lib/mysql/mysql/db.MYD
lrwx------ 1 root root 64 Mar 20 18:26 19 -> /var/lib/mysql/mysql/tables_priv.MYI
l-wx------ 1 root root 64 Mar 20 18:26 2 -> /var/log/mysqld.log
lrwx------ 1 root root 64 Mar 20 18:26 20 -> /var/lib/mysql/mysql/tables_priv.MYD
lrwx------ 1 root root 64 Mar 20 18:26 21 -> /var/lib/mysql/mysql/columns_priv.MYI
lrwx------ 1 root root 64 Mar 20 18:26 22 -> /var/lib/mysql/mysql/columns_priv.MYD
...
lrwx------ 1 root root 64 Mar 20 18:26 25 -> /var/lib/mysql/mysql/servers.MYI
lrwx------ 1 root root 64 Mar 20 18:26 26 -> /var/lib/mysql/mysql/servers.MYD
lrwx------ 1 root root 64 Mar 20 18:26 27 -> /var/lib/mysql/mysql/event.MYI
lrwx------ 1 root root 64 Mar 20 18:26 28 -> /var/lib/mysql/mysql/event.MYD
lrwx------ 1 root root 64 Mar 20 18:26 3 -> /var/lib/mysql/ibdata1
lrwx------ 1 root root 64 Mar 20 18:26 30 -> /var/lib/mysql/mysql/func.MYI
lrwx------ 1 root root 64 Mar 20 18:26 31 -> /var/lib/mysql/mysql/func.MYD
...
lrwx------ 1 root root 64 Mar 20 18:26 37 -> /var/lib/mysql/mysql/help_keyword.MYD
lrwx------ 1 root root 64 Mar 20 18:26 38 -> /var/lib/mysql/mysql/help_relation.MYI
lrwx------ 1 root root 64 Mar 20 18:26 39 -> /var/lib/mysql/mysql/help_relation.MYD
lrwx------ 1 root root 64 Mar 20 18:26 4 -> /tmp/ibGquxvh (deleted)
lrwx------ 1 root root 64 Mar 20 18:26 40 -> /var/lib/mysql/mysql/help_topic.MYI
...
lrwx------ 1 root root 64 Mar 20 18:26 46 -> /var/lib/mysql/mysql/proc.MYI
lrwx------ 1 root root 64 Mar 20 18:26 47 -> /var/lib/mysql/mysql/proc.MYD
lrwx------ 1 root root 64 Mar 20 18:26 48 -> /var/lib/mysql/mysql/slow_log.CSM
lr-x------ 1 root root 64 Mar 20 18:26 49 -> /var/lib/mysql/mysql/slow_log.CSV
lrwx------ 1 root root 64 Mar 20 18:26 5 -> /tmp/ibGbuH88 (deleted)
lrwx------ 1 root root 64 Mar 20 18:26 50 -> /var/lib/mysql/mysql/time_zone.MYI
lrwx------ 1 root root 64 Mar 20 18:26 51 -> /var/lib/mysql/mysql/time_zone.MYD
lrwx------ 1 root root 64 Mar 20 18:26 52 -> /var/lib/mysql/mysql/time_zone_leap_second.MYI
lrwx------ 1 root root 64 Mar 20 18:26 53 -> /var/lib/mysql/mysql/time_zone_leap_second.MYD
...
```

Çok uzun olduğu için çıktıyı keserek paylaşmak durumunda kaldık. Sadece bu işlemin 86 tane açık file descriptor'ı mevcut ancak çok yoğun veritabanı kullanımlarında bu sayı çok daha yüksek (binlerce) olabiliyor. Yukarıdaki örnekte MySQL'in log dosyalarına, yardım dosyalarına, time zone ve çok çeşitli farklı dosyaya eriştiği görülebilir. Hatta `/tmp` dizini altında kullandığı bazı geçici dosyalar silinmiş bile. Böyle bir durumda çok fazla file descriptor harcayabilir, tek başına işletim sisteminin diğer programlara file descriptor ayırabilmesi olanaksız hale gelebilir. Bu durumun önüne geçmek için kernel parametrelerinde çeşitli sınırlandırmalar sağlanır. Bu sınırlandırmalar sistem genelinde olabileceği gibi, kullanıcı bazlı da değişebilir.

Limitler iki çeşittir. Hardlimit ve Softlimit. Hardlimit sadece root tarafından düzenlenebilecek limitlerdir. Softlimit ise bir kullanıcının kendi düzenleyebileceği limittir.

Örneğin biraz önceki sunucuda `mysql` kullanıcısının limitlerini öğrenmek için, bu kullanıcı ile login olduktan sonra aşağıdaki komutları uygulayabiliriz.

```bash
[root@emre ~]# su - mysql
-bash-4.1$ ulimit -Hn
4096
-bash-4.1$ ulimit -Sn
1024
```

Demek ki bu sunucu üzerinde `mysql` kullanıcısının Hardlimit'i 4096, Softlimit'i 1024. Bu şu anlama gelir, bir program `mysql` kullanıcısı olarak çalıştırıldığında, aynı anda 1024'ten fazla file descriptor oluşturamaz. Eğer 1024'ten fazlasına ihtiyaç duyarsa, bu sayıyı kendisi artırabilir, ancak asla Hardlimit olan 4096 sayısını geçemez. Bu sayıyı geçmesi için root yetkisi olan yöneticisinden izin alması gerekir ve ancak root kullanıcısı Hardlimit değerini düzenleyebilir.

Oluşabilecek bir yanlış anlaşılmayı gidermek adına not edelim, bu limitler kullanıcı bazlı olsa bile, kullanıcıların bütün programları için toplanarak giden bir değer değildir. Kullanıcının her bir programı bu limitler dahilinde davranabilir. Yani Hardlimit'i 4096 olan bir kullanıcının, Softlimit'i de uygun ayarlandığında, iki farklı programı ayrı ayrı 4000'er dosya açabilir.

Bir kullanıcının bütün Hardlimit'lerini görmek için aşağıdaki komut kullanılabilir:

```bash
eaydin@eaydin-vt ~ $ ulimit -aH
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 47455
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1048576
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) unlimited
cpu time               (seconds, -t) unlimited
max user processes              (-u) 47455
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
```

Benzer şekilde, kullanıcının bütün Softlimit'leri aşağıdaki gibi görülebilir:

```bash
eaydin@eaydin-vt ~ $ ulimit -aS
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 47455
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 47455
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
```

Burada file descriptor haricindeki sistem limitlerinin de bulunduğu görülebilir. Bu bölümün kapsamı dışında olduğu için maddelerin üzerinden tek tek geçmeyeceğiz.

### Kullanıcı Limitlerini Düzenlemek

Kullanıcı bazlı bu limitleri düzenlemek için `/etc/security/limits.conf` dosyasını düzenlemek gerekir. Örneğin `mysql` kullanıcısı için Softlimit 2048, Hardlimit 8192 olsun istersek, dosya içerisinde şöyle satırlar oluşturmamız gerekir.

```
mysql soft nofile 2048
mysql hard nofile 8192
```

Dosyayı kaydetmek yeterli olacaktır. Ardından yine ilgili kullanıcı ile login olup `ulimit` komutu yardımıyla güncellenmiş değerleri görebiliriz. Modern sistemlerde, bu dosya yerine `/etc/security/limits.d/` dizini altındaki `.conf` uzantılı dosyalar da kullanılabilir ve genellikle bu yöntem tercih edilir (örneğin, `/etc/security/limits.d/mysql.conf`). Bu dizindeki dosyalar, ana `limits.conf` dosyasındaki ayarları geçersiz kılabilir veya tamamlayabilir.

Red Hat, CentOS ve türevi dağıtımlarda `/etc/pam.d/login` (veya `system-auth`, `password-auth` gibi ilgili PAM yapılandırma dosyalarında) `pam_limits.so` modülünün yüklendiğinden emin olmak gerekir. Genellikle aşağıdaki gibi bir satır bulunur:

`session required pam_limits.so`

### Sistem Limitlerini Düzenlemek

Sistemin genel limitini `/proc/sys/fs/file-max` dosyasını okuyarak öğrenebiliriz demiştik. Bu dosya aynı zamanda üzerine yazılabilir bir dosyadır, dolayısıyla bu dosyaya değeri yazarak da kernel parametresini düzenleyebiliriz. Örneğin sistemin limitini 386774'ten 15000'e düşürmek için aşağıdaki komutu kullanabiliriz.

```bash
[root@emre ~]# echo 15000 > /proc/sys/fs/file-max
```

Bunun yerine, `sysctl` komutu ile de kernel parametrelerini düzenleyebiliriz.

```bash
[root@emre ~]# sysctl -w fs.file-max=15000
```

Bu yöntemler ile kernel parametresi doğrudan düzenlendiği için, çalışan sistem üzerinde değişikliğin etkisini hemen görürüz. Ancak sistem bir kez reboot olursa değişiklikler kalıcı olmaz. Eğer değişikliği kalıcı yapmak istersek, `/etc/sysctl.conf` dosyasını veya modern sistemlerde `/etc/sysctl.d/` dizini altındaki `.conf` uzantılı bir dosyayı (örneğin `/etc/sysctl.d/99-filemax.conf`) düzenlemek gerekecektir. Bu dosya içerisinde aşağıdaki parametre yoksa eklemek, varsa değiştirmek gerekir.

```
fs.file-max = 15000
```

Eğer sadece dosyayı değiştirdiysek, yani `sysctl -w fs.file-max=15000` komutuyla düzenleme yapmamışsak, bu sefer kernel'in dosya içerisinden parametreleri yeniden okumasını söylemek gerekir. Bunu da yine `sysctl` komutu ile yaparız.

```bash
[root@emre ~]# sysctl -p /etc/sysctl.conf 
# veya belirli bir dosya için:
# sysctl -p /etc/sysctl.d/99-filemax.conf
# veya tüm .d dizinini yüklemek için (genellikle sistem başlangıcında yapılır):
# sysctl --system
```


# Forkbomb

## Fork Bomb Nedir?

Fork bomb, kendini sürekli olarak kopyalayan (fork eden) ve bu yolla sistem kaynaklarını (özellikle işlem tablosunu ve işlemci zamanını) hızla tüketerek sistemi kullanılamaz hale getirmeyi amaçlayan basit ama etkili bir Denial of Service (DoS) saldırısıdır. Çalıştırıldığında, üstel bir hızla yeni işlemler oluşturur ve kısa sürede sistemin yeni işlem başlatmasını engeller.

## Klasik Bash Fork Bombası

Bash kabuğunda en bilinen fork bombası şu şekildedir:

```bash
:(){ :|:& };:
```

Bu kodun açıklaması şöyledir:

1. **:(){ ... };** : `:` isminde bir fonksiyon tanımlar. Fonksiyon ismi olarak `:` seçilmesi, kodun daha kısa ve gizemli görünmesini sağlar, ancak herhangi bir geçerli fonksiyon ismi de kullanılabilir (örneğin `bomb(){ bomb|bomb& }; bomb`).
2. **:** : Fonksiyonun gövdesi içinde, fonksiyon kendini tekrar çağırır.
3. **|** : İlk çağrının standart çıktısı, ikinci bir çağrıya pipe (boru hattı) ile standart girdi olarak bağlanır. Bu pipe işlemi, her iki tarafın da çalışmasını sağlamak için gereklidir, ancak verinin kendisi önemli değildir.
4. **:** : İkinci çağrı yapılır.
5. **&** : İkinci çağrı (`:|:`) arka planda çalıştırılır. Bu, fonksiyonun hemen geri dönmesini ve döngünün hızla devam etmesini sağlar.
6. **;** : Fonksiyon tanımı sonlandırılır.
7. **:** : Tanımlanan `:` fonksiyonu ilk kez çağrılarak bomba tetiklenir.

Bu zincirleme reaksiyon sonucunda, her çalışan fonksiyon iki yeni fonksiyonu tetikler ve işlem sayısı katlanarak artar (`1 -> 2 -> 4 -> 8 -> 16 -> ...`).

## Fork Bombasına Karşı Korunma: `ulimit` ve `nproc`

Modern Linux sistemleri, fork bombalarının etkisini sınırlamak için kullanıcı başına kaynak limitleri uygular. Bu limitlerden en önemlisi, bir kullanıcının aynı anda sahip olabileceği maksimum işlem sayısıdır (`nproc`).

Bu limitler `ulimit` komutu ile görüntülenebilir ve (soft limitler için) ayarlanabilir:

```bash
# Mevcut kullanıcı için soft nproc limitini göster
ulimit -Su 

# Mevcut kullanıcı için hard nproc limitini göster
ulimit -Hu

# Tüm soft limitleri göster
ulimit -aS

# Tüm hard limitleri göster
ulimit -aH 
```

Örnek `ulimit -aS` çıktısı:

```
...
max user processes              (-u) 4096 
...
```

Bu örnekte, kullanıcının aynı anda en fazla 4096 işlem başlatabileceği görülmektedir (soft limit).

Bir fork bombası çalıştırıldığında, işlem sayısı hızla bu limite ulaşır. Limit aşıldığında, sistem yeni işlemler (fork) oluşturamaz ve aşağıdaki gibi hatalar verir:

```bash
-bash: fork: retry: No child processes
-bash: fork: Resource temporarily unavailable 
```

Bu hatalar, fork bombasının `nproc` limiti tarafından durdurulduğunu gösterir. Sistem yavaşlayabilir ancak tamamen kullanılamaz hale gelmez ve genellikle yönetici müdahalesi ile (örneğin, bombayı başlatan kullanıcının işlemlerini sonlandırarak) kurtarılabilir.

## Limitlerin Yapılandırılması

Kullanıcı bazlı işlem limitleri genellikle `/etc/security/limits.conf` dosyasında veya daha modern sistemlerde `/etc/security/limits.d/` dizini altındaki dosyalarda (örneğin, `20-nproc.conf`) ayarlanır.

Örnek bir `/etc/security/limits.d/20-nproc.conf` dosyası:

```
# Kullanıcıların yanlışlıkla fork bombası başlatmasını önlemek için
# varsayılan işlem limiti.

*          soft    nproc     4096
root       soft    nproc     unlimited
#emre       hard    nproc     8192 
```

* `*`: Root dışındaki tüm kullanıcılar için geçerli kural.
* `soft`: Uygulanan başlangıç limiti (soft limit). Kullanıcı bu limiti hard limite kadar artırabilir.
* `hard`: Kullanıcının ulaşabileceği mutlak üst limit (hard limit). Sadece root tarafından artırılabilir.
* `nproc`: Limitlenen kaynağın türü (number of processes).
* `4096`: Limit değeri. `unlimited` ise limitsiz anlamına gelir.

Bu yapılandırma dosyaları, PAM (Pluggable Authentication Modules) aracılığıyla, genellikle `pam_limits.so` modülü kullanılarak kullanıcı oturumları başladığında uygulanır.

Fork bombaları, kaynak limitlerinin ve dikkatli sistem yönetiminin önemini gösteren klasik bir örnektir.


# Named Pipe

Bu bölümde programların standart girdi ve çıktılarını birbirlerine veya çeşitli dosyalara yönlendirme işlemlerinin detaylarını gördük. Özellikle UNIX pipeline'ı oluşturan bu süreçte, genellikle programları birbirleriyle bağlarken `|` işaretinin nasıl kullanıldığını gördük.

Bu kullanımdaki temel problemler, programlar arasındaki bağlantının tek seferlik yapılması, tek yönlü olması ve tek yazılım tarafından kullanılabilmesi. Örneğin bir programın çıktısının birden fazla program tarafından girdi olarak kullanılmasını sağlamak, veya birden fazla programın girdi sağlayabileceği ortam sağlamak mümkün olmaz.

Bunun için *named pipe* denilen dosyalar kullanılır. Hatırlarsanız daha önce "UNIX üzerinde her şey bir dosyadır" demiştik. Burada da özel bir dosya tipinden bahsediyoruz. Sistem üzerinde öyle bir dosya tanımlanır ki, bu dosyaya birden fazla program yazabilir, ve bu dosyayı birden fazla program okuyabilir. Üstelik bu dosya hiç yer kaplamaz. Aslında daha önce kullandığımız pipe işleminin sadece iki program arasında değil, birden fazla program arasında kullanılmasına olanak sağlar. Bunu yapmak için dosya sistemi üzerinde ilgili pipe'ı isimlendirmemiz gerektiğinden, bunlara *named pipe* denilir. Böyle olunca da, daha önce kullandığımız pipe işaretlerine *anonymous pipe* (anonim pipe) veya *regular pipe* (normal pipe) denilir.

Named pipe'lar, üzerine yazılan verinin aynı sırayı koruyarak okunmasını sağlarlar. Kısacası ilk yazdığımız veri, ilk okunacak veridir. Bu tip sistemlere *First In First Out*'un kısaltması olan FIFO denilir. Yani işleme alınacak verilerde öncelik, en eski oluşturulan veriye tanınır. Örneğin bunun bir alternatifi, *Last In First Out*'un kısaltması olan LIFO'lardır. Ancak named pipe'lar, FIFO şeklinde çalıştığı için, aşağıdaki komut ile bir named pipe oluşturulur.

```
eaydin@eaydin-vt ~/devel/namedpipe $ mkfifo mario
```

Bu işlem sonucunda aslında `~/devel/namedpipe` dizini içinde `mario` isimli özel bir dosya oluşmuştur. Bu dizinin içeriğine bakacak olursak:

```
eaydin@eaydin-vt ~/devel/namedpipe $ ls -l
total 0
prw-rw-r-- 1 eaydin eaydin 0 Mar 16 15:39 mario
```

Burada `mario`'nun dosya tipinin **p** olduğu görülüyor. Bu, dosyanın pipe olduğunu ifade etmektedir. Gördüğünüz üzere dosyanın boyutu da 0 Byte'dır. Yani disk üzerinde yer kaplamaz.

Eğer aşağıdaki gibi ufak bir script yazarsak, çalıştırıldığında her saniye mevcut tarih/saati standart çıktıya yazdırmasını sağlayabiliriz. Bu script'i `telltime.sh` olarak kaydettiğimizi düşünelim.

```
eaydin@eaydin-vt ~/devel/namedpipe $ cat telltime.sh 
while true; do
date
sleep 1
done
```

Eğer bu scripti çalıştırıp standart çıktısını `mario`'ya yönlendirirsek, sonra başka bir terminal üzerinden `mario`'yu okursak, her saniye tarih/saati görmeyi bekleriz.

```
eaydin@eaydin-vt ~/devel/namedpipe $ ./telltime.sh > mario
```

```
eaydin@eaydin-vt ~/devel/namedpipe $ cat < mario
Fri Mar 16 16:05:17 +03 2018
Fri Mar 16 16:05:18 +03 2018
Fri Mar 16 16:05:19 +03 2018
Fri Mar 16 16:05:20 +03 2018
Fri Mar 16 16:05:21 +03 2018
Fri Mar 16 16:05:22 +03 2018
Fri Mar 16 16:05:23 +03 2018
Fri Mar 16 16:05:24 +03 2018
Fri Mar 16 16:05:25 +03 2018
^C
```

Tahmin edeceğiniz üzere, mario'yu birden fazla programın okumasını da sağlayabilirdik.

Şimdi bir başka program yazalım, ve bu program da iki saniyede bir VeriTeknik sözcüğünü standart çıktıya yazsın.

```
eaydin@eaydin-vt ~/devel/namedpipe $ cat tellname.sh 
while true; do
echo VeriTeknik
sleep 2
done
```

Biraz önce çalıştırdığımız `./telltime.sh > mario` komutu hala çalışmaya devam ederken, bir de `./tellname.sh > mario` komutunu farklı terminalde çalıştırabiliriz. Böylece `telltime` scripti her saniye `mario`'ya saati yazacak, `tellname` scripti ise her iki saniyede bir `mario`'ya `VeriTeknik` yazacaktır. Sonucu yine farklı bir terminalde `mario`'yu okuyarak gözleyebiliriz.

```
eaydin@eaydin-vt ~/devel/namedpipe $ cat < mario
Fri Mar 16 16:09:21 +03 2018
Fri Mar 16 16:09:22 +03 2018
Fri Mar 16 16:09:23 +03 2018
Fri Mar 16 16:09:24 +03 2018
VeriTeknik
Fri Mar 16 16:09:25 +03 2018
Fri Mar 16 16:09:26 +03 2018
VeriTeknik
Fri Mar 16 16:09:27 +03 2018
Fri Mar 16 16:09:28 +03 2018
VeriTeknik
Fri Mar 16 16:09:29 +03 2018
Fri Mar 16 16:09:30 +03 2018
VeriTeknik
Fri Mar 16 16:09:31 +03 2018
Fri Mar 16 16:09:32 +03 2018
VeriTeknik
Fri Mar 16 16:09:33 +03 2018
Fri Mar 16 16:09:34 +03 2018
Fri Mar 16 16:09:35 +03 2018
^C
```

Özellikle başlarda ve sonlarda 2'den fazla saat satırı görmeniz normal, çünkü `tellname` scriptini arada çalıştırıp durdurduk. Yukarıdaki örnekten `tellname` scriptini saat 16:09:24'te çalıştırdığımızı ve 16:09:33 veya 16:09:34'te durdurduğumuzu anlayabiliriz. Yani `mario` pipe'ına aynı anda yeni programlar veri yazıp durdurabilir, ve okuyan taraf sadece sonuçları görerek etkilenir. Dosyayı yeniden açıp kapatmasına bile ihtiyaç duymaz.

Named pipe'lar hakkında GNU/Linux manual sayfalarında önemli bir bilgi yer alır.

> The FIFO must be opened on both ends (reading and writing) before data can be passed. Normally, opening the FIFO blocks until the other end is opened also.

Yani bir named pipe oluşturduğumuzda, eğer aynı anda okuyan ve yazan birileri varsa veri akışı sağlanır. Yoksa bir taraftan sürekli yazsanız bile, bunu okuyan birileri olmadığı sürece o veri kaybolur. Tıpkı `/dev/null` dosyasına yazmışsınız gibi veri hiçbir yere kaydedilmez.

Named pipe'lar ile yapılan işlemlerin dosya sisteminde inode oluşturmak dışında herhangi bir yük oluşturmadığını hatırlatmakta fayda var. Birden fazla programın birbiriyle iletişim kurmasını sağlayan bu mekanizma tamamen çekirdek (kernel) tarafından idare edilir.

Oluşturduğunuz bir named pipe'ı `rm` komutuyla kolayca silebilirsiniz.

```
eaydin@eaydin-vt ~/devel/namedpipe $ rm mario
```


# Gelişmiş Terminal Komutları

Bu bölümde, temel komutların ötesine geçerek Linux terminalinin gücünü daha etkin kullanmanızı sağlayacak bazı gelişmiş araçlar ve teknikler incelenecektir. Tarih/saat ayarlamadan sistem yükünü izlemeye, metin işleme araçlarından dosya indirme ve sunma yöntemlerine kadar çeşitli konulara değinilecektir.

İncelenecek konular şunlardır:

* [Tarih ve Saat Ayarlama](/gelismis-terminal-komutlari/tarih-ve-saat-ayarlama) (`date`, `timedatectl`, `ntp`)
* [Sistem Yükünü İzleme](/gelismis-terminal-komutlari/sistem-yuekuenue-izleme) (`top`, `htop`, `atop` vb.)
* [patch ve diff](/gelismis-terminal-komutlari/patch-ve-diff) (Dosyalar arasındaki farkları bulma ve uygulama)
* [xargs](/gelismis-terminal-komutlari/xargs) (Standart girdiyi komut argümanlarına dönüştürme)
* [awk ve sed](/gelismis-terminal-komutlari/awk-ve-sed) (Güçlü metin işleme araçları)
* [egrep ve Regular Expressions](/gelismis-terminal-komutlari/egrep-ve-regular-expressions) (Desen eşleştirme ve metin arama)
* [rename](/gelismis-terminal-komutlari/rename) (Toplu dosya yeniden adlandırma)
* [Imagemagick ve Görüntü Dosyaları](/gelismis-terminal-komutlari/imagemagick-ve-goeruentue-dosyalari) (Komut satırından resim işleme)
* [wget](/gelismis-terminal-komutlari/wget) (Dosya indirme aracı)
* [Python ile Dosya Sunuculuğu](/gelismis-terminal-komutlari/python-ile-dosya-sunuculugu) (Basit HTTP sunucusu oluşturma)


# Tarih ve Saat Ayarlama

## Sistem Saati

Linux üzerinde tarih ve saat ayarlama işlemleri **date** komutu ile gerçekleştirilir. Komutu tek başına yazdığınızda tarih ve saati çıktı olarak verir.

```bash
date
Sun Nov 15 19:22:23 EET 2015
```

date komutu ile istediğimiz biçimde çıktı alabiliriz.

```bash
date +%d_%m_%Y
15_11_2015
```

Daha kompleks işlemler için boşluklu parametreleri çift tırnak içinde birleştirip tek parametre olarak programa sunmak gerekir.

```bash
date +"Ay:%m / Yıl:%y"
Ay:11 / Yıl:15
```

Saati ve tarihi ayarlamak içinse aşağıdaki gibi bir yol izlenebilir.

```bash
date -s "2 NOV 2014 17:45:12"
Sun Nov 2 17:45:12 EET 2014
```

Sadece saati değiştirmek için,

```bash
date -s "15:12:13"
Sun Nov 2 15:12:13 EET 2014
```

Veya dilediğiniz biçimde tarih belirtmek için,

```bash
date +%Y%m%d%T -s "20120423 09:15:12"
```

## Fiziksel Saat

Sistem üzerine yazılan saatler, bilgisayarın pil ile tutulan fiziksel saatine doğrudan kaydedilmez. Fiziksel saatteki bilgiye erişmek için **hwclock** komutu kullanılmalıdır.

Fiziksel saatteki bilgiyi okumak için

```bash
hwclock -r
Sun 15 Nov 2015 07:37:57 PM EET  -0.960295 seconds
```

Yukarıdaki çıktıda -0.960295 saniye'lik bir fark görünüyor. Bu komutu verdiğimiz an ile, cihazdan okuduğumuz saat arasındaki fark. Kısacası cihaz bize neredeyse 1 saniye içerisinde cevap vermiş. Bu süre zarfında hwclock komutunun yaptıklarını daha detaylı görmek için **-D** (debug) parametresiyle çalıştırabilirsiniz.

```bash
hwclock -D
hwclock from util-linux 2.20.1
Using /dev interface to clock.
Last drift adjustment done at 1435275720 seconds after 1969
Last calibration done at 1435275720 seconds after 1969
Hardware clock is on UTC time
Assuming hardware clock is kept in UTC time.
Waiting for clock tick...
...got clock tick
Time read from Hardware Clock: 2015/11/15 17:39:39
Hw clock time : 2015/11/15 17:39:39 = 1447609179 seconds since 1969
Sun 15 Nov 2015 07:39:39 PM EET  -0.969248 seconds
```

Fiziksel saatteki değeri okuyup, sistem saatinizi bununla güncellemek isteyebilirsiniz. Aslında bilgisayarlarınızın açılışta yaptığı bir işlemdir bu. Böylelikle sisteminize hiç enerji verilmediği durumlarda saat pili ile sistem geçen zamanı tutmaya devam eder, sisteminiz tekrar açıldığında bu cihazdan (RTC: Real Time Clock) saati okur ve kendi tarihini bu değerle günceller.

```bash
hwclock -s
```

Öte yandan, **date** komutu ile sistem saatini güncellemeyi öğrenmiştik. Bu komut ile sistem saatinizi güncelledikten sonra fiziksel saatin değerinin değişmemesi normal. Eğer fiziksel saatin değerini de sistem saatinizdekine ayarlamak isterseniz, bu bilgiyi RTC modülüne yazmanız gerekir.

```bash
hwclock -w
```

## NTP ile Zaman Senkronizasyonu (Modern Yöntemler)

NTP (Network Time Protocol), ağ üzerindeki sunuculardan hassas zaman bilgisi alarak sistem saatini doğru tutmak için kullanılan standart protokoldür. Modern Linux dağıtımları genellikle zaman senkronizasyonu için `systemd-timesyncd` veya `chrony` servislerini kullanır. `ntpdate` komutu çoğu sistemde artık önerilmemektedir (deprecated).

### systemd-timesyncd

Birçok modern dağıtımda varsayılan olarak gelen basit bir NTP istemcisidir. Genellikle ek kurulum gerektirmez.

**Durumu Kontrol Etme:**`timedatectl status` komutu ile hem zaman ayarlarını hem de NTP senkronizasyon durumunu görebilirsiniz:

```bash
timedatectl status
               Local time: Cum 2025-03-28 02:05:10 +03
           Universal time: Per 2025-03-27 23:05:10 UTC
                 RTC time: Per 2025-03-27 23:05:10
                Time zone: Europe/Istanbul (+03, +0300)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no 
```

`System clock synchronized: yes` ve `NTP service: active` satırları senkronizasyonun çalıştığını gösterir.

**Etkinleştirme/Devre Dışı Bırakma:**`timedatectl` komutu ile NTP senkronizasyonunu açıp kapatabilirsiniz:

```bash
# NTP senkronizasyonunu etkinleştir
sudo timedatectl set-ntp true

# NTP senkronizasyonunu devre dışı bırak
sudo timedatectl set-ntp false 
```

`systemd-timesyncd` servisi genellikle `/etc/systemd/timesyncd.conf` dosyasından yapılandırılır ve varsayılan olarak dağıtımın belirlediği NTP sunucu havuzlarını (pool) kullanır.

### chrony

`ntpd`'ye göre daha modern, hızlı ve esnek bir NTP istemcisi ve sunucusudur. Özellikle sık sık uyku moduna giren veya ağ bağlantısı kararsız olan sistemler için daha uygundur. Bazı dağıtımlar (örneğin RHEL/CentOS 7 ve sonrası) varsayılan olarak `chrony` kullanır.

**Kurulum (Gerekliyse):**

```bash
# Debian/Ubuntu
sudo apt install chrony

# RHEL/CentOS/Fedora
sudo dnf install chrony 
```

**Durumu Kontrol Etme:**`chronyc` komutu ile senkronizasyon durumu ve kaynaklar hakkında detaylı bilgi alınabilir:

```bash
chronyc sources -v
```

```bash
chronyc tracking
```

**Yapılandırma:**`chrony` genellikle `/etc/chrony/chrony.conf` (veya `/etc/chrony.conf`) dosyasından yapılandırılır. Kullanılacak NTP sunucuları bu dosyada `server` veya `pool` direktifleri ile belirtilir.

**Servis Yönetimi:**`chrony` bir sistem servisidir ve `systemctl` ile yönetilir:

```bash
sudo systemctl start chronyd
sudo systemctl enable chronyd
sudo systemctl status chronyd
```

**Önemli Not:** Sistemde aynı anda sadece bir NTP istemcisinin (örneğin `systemd-timesyncd` veya `chrony` veya eski `ntpd`) aktif olması önerilir. Çakışmaları önlemek için kullanılmayacak olan servisleri devre dışı bırakmak gerekir.

Zaman senkronizasyonu yapıldıktan sonra, sistem saatindeki değişikliğin donanım saatine (RTC) yazılması genellikle bu servisler tarafından otomatik olarak veya periyodik olarak yapılır. Ancak manuel olarak yapmak isterseniz `hwclock -w` komutunu kullanabilirsiniz.

## Saat Diliminin Ayarlanması

Sistem saat dilimi (timezone), sistemin yerel saati doğru göstermesi için önemlidir.

### timedatectl ile Ayarlama (Önerilen Yöntem)

Modern systemd tabanlı sistemlerde saat dilimini ayarlamanın en kolay ve önerilen yolu `timedatectl` komutunu kullanmaktır.

**Mevcut Saat Dilimini Görme:**

```bash
timedatectl status | grep "Time zone"
# veya sadece:
timedatectl
```

**Kullanılabilir Saat Dilimlerini Listeleme:**

```bash
timedatectl list-timezones
# Belirli bir bölgeyi filtrelemek için grep kullanılabilir:
timedatectl list-timezones | grep Europe
timedatectl list-timezones | grep Istanbul
```

**Saat Dilimini Ayarlama:**\
Örneğin, saat dilimini İstanbul olarak ayarlamak için:

```bash
sudo timedatectl set-timezone Europe/Istanbul
```

Bu komut, gerekli sembolik linki (`/etc/localtime` -> `/usr/share/zoneinfo/...`) otomatik olarak oluşturur veya günceller.

### Manuel Yöntem (Eski veya systemd olmayan sistemler)

`timedatectl` komutunun bulunmadığı sistemlerde veya manuel olarak yapmak istenirse, `/etc/localtime` dosyası, `/usr/share/zoneinfo` altındaki doğru saat dilimi dosyasına işaret eden bir sembolik link olarak ayarlanır.

Önce mevcut link (varsa) kaldırılır, sonra yenisi oluşturulur:

```bash
# Önce mevcut linki kaldır (varsa)
sudo rm /etc/localtime

# Yeni sembolik linki oluştur (örnek: İstanbul)
sudo ln -s /usr/share/zoneinfo/Europe/Istanbul /etc/localtime 
```

Bazı eski sistemlerde `/etc/timezone` gibi metin tabanlı bir yapılandırma dosyası da bulunabilir ve bunun da güncellenmesi gerekebilir (örneğin içine `Europe/Istanbul` yazmak). Ancak modern sistemlerde genellikle sadece `/etc/localtime` linki yeterlidir.

`/etc/localtime` dosyası, saat dilimi kurallarını içeren *binary* bir dosyaya işaret eden bir sembolik linktir. Bu dosyanın doğrudan kopyalanması yerine sembolik link kullanılması, `tzdata` paketi güncellendiğinde saat dilimi kurallarının da otomatik olarak güncellenmesini sağlar. `/etc/localtime` dosyasının veya linkinin olmaması durumunda, sistem genellikle saat dilimini UTC (GMT+0) olarak varsayar.


# Sistem Yükünü İzleme

## top

Linux üzerinde sistem kaynaklarınızı ve çalışan işlemleri gerçek zamanlı olarak izlemek için kullanılan temel programlardan birisi **top** programıdır. Varsayılan olarak işlemleri CPU kullanımına göre sıralı olarak gösterir.

**`top` Ekranını Anlamak:**

* **İlk Satır:** `uptime` komutunun çıktısına benzer bilgiler içerir: mevcut saat, sistemin ne kadar süredir çalıştığı (up time), kaç kullanıcının bağlı olduğu ve sistem yük ortalamaları (load average) (son 1, 5 ve 15 dakika için). Yük ortalaması, çalışmak için bekleyen veya çalışan işlem sayısının bir ölçüsüdür; 1.00 değeri tek çekirdekli bir CPU'nun tam kapasite çalıştığını gösterir. Çok çekirdekli sistemlerde bu değer çekirdek sayısı ile orantılı olarak artabilir.
* **İkinci Satır (Tasks):** Toplam işlem sayısı ve durumlarına göre (çalışan, uyuyan, durmuş, zombi) dağılımı.
* **Üçüncü Satır (%Cpu(s)):** CPU kullanımının farklı modlardaki yüzdesi: `us` (user space), `sy` (system/kernel space), `ni` (nice değeri değiştirilmiş user space), `id` (idle/boşta), `wa` (I/O bekleme), `hi` (hardware interrupts), `si` (software interrupts), `st` (steal time - sanal makinelerde).
* **Dördüncü/Beşinci Satır (Mem/Swap):** Fiziksel bellek (RAM) ve takas alanı (swap) kullanımı hakkında bilgi (toplam, kullanılan, boş, buffer/cache).
* **İşlem Listesi:** Çalışan işlemler ve onlarla ilgili bilgiler (PID, kullanıcı, öncelik (PR), nice değeri (NI), sanal bellek (VIRT), fiziksel bellek (RES), paylaşılan bellek (SHR), durum (S), %CPU, %MEM, çalışma süresi (TIME+), komut (COMMAND)).

![](/files/-L9H1_lCojaGfPp7Gqcs)

*Tipik bir `top` ekranı*

**Etkileşimli `top` Komutları:**

`top` çalışırken aşağıdaki tuşlarla etkileşimde bulunabilirsiniz:

* **`1`**: Her bir CPU çekirdeğinin kullanımını ayrı ayrı gösterir/gizler.
* **`h`** veya **`?`**: Yardım ekranını gösterir.
* **`q`**: `top` programından çıkar.
* **`k`**: Bir işleme sinyal göndermek (genellikle sonlandırmak) için kullanılır. PID ve sinyal numarası (varsayılan 15/SIGTERM) istenir.
* **`r`**: Bir işlemin nice değerini (önceliğini) değiştirmek için kullanılır (renice). PID ve yeni nice değeri istenir.
* **`M`**: İşlemleri bellek kullanımına (%MEM) göre sıralar.
* **`P`**: İşlemleri CPU kullanımına (%CPU) göre sıralar (varsayılan).
* **`u`**: Belirli bir kullanıcının işlemlerini filtreler.
* **`f`**: Gösterilecek alanları (sütunları) ve sıralama alanını seçmek için kullanılır.
* **`E`**: Bellek birimlerini (KiB, MiB, GiB vb.) değiştirir.
* **`z`**: Renkli gösterimi açar/kapatır.

![](/files/-L9H1_ljwe31TCbBWrHl)

*Her CPU çekirdeğini ayrı gösteren `top` ekranı (`1` tuşuna basıldıktan sonra)*

**htop**

`top` programının renklendirilmiş, daha kullanıcı dostu ve etkileşimli bir alternatifidir. Genellikle sistemlerde önyüklü gelmez, ancak paket yöneticisi ile kolayca kurulabilir (`sudo apt install htop` veya `sudo dnf install htop`).

`htop`'ın avantajları:

* Renkli ve daha okunaklı arayüz.
* Fare ile veya ok tuşları ile işlemler arasında gezinme ve seçme.
* Fonksiyon tuşları (F1-F10) ile kolayca işlem sonlandırma (F9 - Kill), nice değerini değiştirme (F7/F8 - Nice +/-), arama (F3 - Search), sıralama (F6 - SortBy), ağaç görünümü (F5 - Tree) gibi işlemleri yapma.
* Sistem yükü, bellek ve swap kullanımı için daha görsel çubuklar.
* Kolay yapılandırılabilir arayüz (F2 - Setup).

![](/files/-L9H1_nZBdKWjon6thBf)

*htop ekran görüntüsü*

## free

Sistemin genel bellek tüketimini görmek için **free** komutu kullanılabilir.

Sistemin genel bellek (RAM) ve takas alanı (swap) kullanımını görmek için **free** komutu kullanılır.

```bash
free
              total        used        free      shared  buff/cache   available
Mem:        7947480     6307236      851532      482716     1640244     1640244
Swap:       7193596         276     7193320
```

* **total:** Toplam fiziksel bellek/swap alanı.
* **used:** Kullanılan bellek/swap alanı.
* **free:** Tamamen boş olan bellek/swap alanı.
* **shared:** Birden fazla işlem tarafından paylaşılan bellek (genellikle tmpfs).
* **buff/cache:** Çekirdek tarafından tampon (buffer) ve sayfa önbelleği (page cache) için kullanılan bellek. Bu bellek, ihtiyaç duyulduğunda uygulamalar için serbest bırakılabilir.
* **available:** Yeni uygulamaların başlatılması için (swap kullanmadan) kullanılabilecek tahmini bellek miktarı. `free` ve `buff/cache`'in bir kısmını içerir ve genellikle sistemin gerçek boş bellek durumunu `free` sütunundan daha iyi yansıtır.

Daha okunaklı (Megabyte, Gigabyte cinsinden) çıktı almak için `-h` parametresi kullanılır:

```bash
free -h
              total        used        free      shared  buff/cache   available
Mem:           7.6G        6.0G        831M        471M        1.6G        1.6G
Swap:          6.9G        276K        6.9G
```

Eski `free` sürümlerinde görülen `- / + buffers / cache` satırı artık kullanılmamaktadır ve `available` sütunu daha doğru bir bilgi verir.

## atop

Sistem kaynaklarının tümünü görmek istediğinizde en iyi seçeneklerden birisi atop'tır. Tüm donanımı ve prosesleri aynı pencerede görüntüleyebilen uygulama, yavaşlamaya neden olan donanım ya da yazılımın kolayca bulunabilmesini sağlamaktadır. Yapı olarak top'a çok benzer ancak daha detaylıdır ve sorunlu kaynakları daha parlak renkte gösterir.

![](/files/-L9H1_oLD1MG6x8-p8jH)

## kill

**top** kullanılırken işlemleri öldürmek mümkündür. Ekranda **k** tuşuna bastığınızda, doğrudan en üstteki işlem seçilecektir. Bunun dışında bir işlem öldürülmek istenirse, ilgili işlemin PID'si yazılabilir. Ardından hangi sinyal ile öldürüleceği belirtilmelidir. Genel kanı **15** sinyali ile öldürmektir.

![](/files/-L9H1_ol6WZzlEpwFmaq)

`top` veya `htop` içinden işlem sonlandırma genellikle arka planda `kill` komutunu kullanır. `kill` komutu, belirtilen PID'ye sahip işleme bir sinyal gönderir.

```bash
# 6392 PID'li işleme varsayılan sinyali (SIGTERM) gönder
kill 6392

# 6392 PID'li işleme SIGTERM (15) sinyalini gönder
kill -15 6392 
# veya
kill -TERM 6392

# 6392 PID'li işleme SIGKILL (9) sinyalini gönder (zorla kapatma)
kill -9 6392
# veya
kill -KILL 6392
```

* **SIGTERM (15):** Programa sonlanması için nazik bir istek gönderir. Program bu sinyali yakalayıp dosyalarını kaydedebilir, bağlantılarını kapatabilir ve düzgün bir şekilde çıkabilir. Genellikle ilk denenmesi gereken sinyal budur.
* **SIGKILL (9):** Programa sonlanması için zorlayıcı bir komut gönderir. Program bu sinyali yakalayamaz veya görmezden gelemez; çekirdek tarafından anında sonlandırılır. Bu, veri kaybına veya sistemde tutarsızlıklara yol açabilir, bu yüzden sadece SIGTERM işe yaramadığında kullanılmalıdır.
* **SIGHUP (1):** "Hang Up" sinyalidir. Birçok servis (daemon), bu sinyali aldığında yapılandırma dosyalarını yeniden okumak veya kendini yeniden başlatmak (restart) üzere programlanmıştır (örneğin, Apache, Nginx).
* **SIGINT (2):** "Interrupt" sinyalidir. Genellikle terminalde çalışan bir programa `CTRL+C` gönderildiğinde bu sinyal iletilir.

Sistemdeki tüm sinyallerin listesini görmek için `kill -l` komutu kullanılabilir.

**pkill ve killall:**

PID yerine işlem adına veya başka kriterlere göre sinyal göndermek için `pkill` ve `killall` komutları daha kullanışlıdır:

```bash
# Adı "firefox" olan tüm işlemlere SIGTERM gönder
pkill firefox

# "emre" kullanıcısına ait tüm "sleep" işlemlerine SIGKILL gönder
pkill -9 -u emre sleep

# Adı tam olarak "apache2" olan tüm işlemlere SIGHUP gönder (yapılandırmayı yeniden yükle)
killall -HUP apache2 
```

Bu komutları kullanırken dikkatli olunmalıdır, çünkü yanlışlıkla istenmeyen işlemleri sonlandırabilirler.

## uptime

Sistem hakkında bilgi edinmeyi sağlayan bir diğer komut **uptime** komutudur. Sistemin ne kadar zamandır çalıştığını, kaç kişinin (terminalin) açık olduğunu, son birkaç dakikanın işlemci yükünün ortalamasını gösterir.

Sistemin ne zaman başlatıldığını görmek için `who -b` komutu da oldukça faydalıdır.

Öte yandan sisteme bağlı terminallerin bir listesini elde etmek için `w` programı kullanılabilir.

## ps

**ps** programı (*process status*), sistemde o an çalışan işlemler hakkında anlık bilgi almak için kullanılır. `top` veya `htop` gibi sürekli güncellenmez, çalıştırıldığı andaki durumu gösterir.

İki yaygın kullanım stili vardır:

1. **BSD Stili:** Genellikle `-` olmadan kullanılan parametreler.

   ```bash
   ps aux 
   ```

   * `a`: Tüm kullanıcılara ait işlemleri gösterir (terminali olanlar).
   * `u`: Kullanıcı odaklı formatta gösterir (sahip, CPU/MEM kullanımı vb.).
   * `x`: Terminali olmayan işlemleri de (servisler vb.) gösterir.
2. **System V Stili:** Genellikle `-` ile başlayan parametreler.

   ```bash
   ps -ef
   ```

   * `-e`: Tüm işlemleri gösterir (`a` ve `x`'in birleşimi gibi).
   * `-f`: Tam formatta listeleme yapar (UID, PID, PPID, C, STIME, TTY, TIME, CMD).

Her iki komut da benzer bilgileri farklı formatlarda sunar. Çıktı genellikle uzundur, bu yüzden `less`, `grep` gibi araçlarla birlikte kullanılır:

```bash
ps aux | less
ps -ef | grep apache
```

İşlem ağacını (hangi işlemin hangisini başlattığını) hiyerarşik olarak görmek için `pstree` komutu veya `ps`'in bazı özel formatlama seçenekleri (`ps axjf` veya `ps -ejH`) kullanılabilir.

```bash
pstree
```

GNU/Linux üzerinde her zaman 1 numaralı **PID**'ye (Process ID) sahip işlem, sistemin başlangıç işlemidir (genellikle `init` veya modern sistemlerde `systemd`). Diğer tüm işlemler doğrudan veya dolaylı olarak bu işlem tarafından başlatılır (fork edilir). 1 numaralı işlem sonlandırılırsa sistem durur, bu nedenle çekirdek tarafından korunur ve genellikle `SIGKILL` gibi sinyallere yanıt vermez. Bir işlemin başlattığı işleme "child process", başlatan işleme ise "parent process" denir. Genellikle bir parent process öldüğünde, child process'leri de sonlanır veya 1 numaralı işlem tarafından evlat edinilir (adopted).

## nice

Linux üzerinde işlemlerin CPU zamanlayıcısındaki önceliği, "nice" değeri ile ayarlanabilir. Nice değeri, bir işlemin diğer işlemlere karşı ne kadar "nazik" (nice) olacağını belirtir.

* Nice değeri **-20** (en yüksek öncelik, en az nazik) ile **+19** (en düşük öncelik, en nazik) arasında değişir.
* Varsayılan nice değeri genellikle **0**'dır.
* Daha düşük nice değerine sahip işlemler, CPU zamanlayıcısı tarafından daha öncelikli olarak çalıştırılır.
* Normal kullanıcılar sadece kendi işlemlerinin nice değerini artırabilir (önceliği düşürebilir, yani daha "nazik" yapabilir). Nice değerini düşürmek (önceliği artırmak) için genellikle root yetkisi gerekir.

**top** ve `htop` komutlarının çıktısındaki **NI** sütunu, ilgili işlemin nice değerini gösterir.

Bir programı belirli bir *nice* değeri ile çalıştırmak istersek, programı çalıştırma esnasında bu değeri belirtmek gerekir.

```bash
nice -n 12 crc8
```

Öte yandan, mevcut bir programın *nice* değerini değiştirmek istersek, programın **PID** değerini parametre olarak vermek gerekir.

```bash
renice -3 5486
```

Komutların mevcut nice değerini **ps** ile öğrenmek için, ps çıktısından bunu talep edebiliriz.

```bash
ps ax -o pid,ni,cmd
```

**PROBLEM:** Sistem üzerinde 20 dakikadan daha uzun süredir çalışan belirli bir işlemi bulun. **ps** komutunun uygun parametreleriyle (`etime` veya `bsdtime` gibi) elde edilebilir. Bu işlemi öldürün.


# patch ve diff

İki dosya arasındaki farkı görmenin en kolay yolu, **diff** komutunu kullanmaktır. Örneğin

```bash
eaydin@dixon ~/calisma $ cat test.txt 
birinci satir
ikinci satir
ucuncu satir
eaydin@dixon ~/calisma $ cat test2.txt 
birinci satir
ikinci baska satir
eaydin@dixon ~/calisma $ diff test.txt test2.txt 
2,3c2
< ikinci satir
< ucuncu satir
---
> ikinci baska satir
```

diff çıktısına baktığımızda, dosyalar arasında fark olduğunu görebiliyoruz. Farkın belirtildiği satırların üstündeyse **2,3c2** gibi bir ifade var. Bu ifade **patch** programının yorumlaması için gerekiyor. Bir patch dosyasını oluşturmak için diff programının **-u** parametresi kullanılabilir.

```bash
eaydin@dixon ~/calisma $ diff -u test.txt test2.txt 
--- test.txt    2015-11-28 14:56:16.268143061 +0200
+++ test2.txt    2015-11-28 14:56:27.888143494 +0200
@@ -1,3 +1,2 @@
 birinci satir
-ikinci satir
-ucuncu satir
+ikinci baska satir
```

Yukarıda, `test.txt` dosyasından `test2.txt` dosyası türetmek istiyorsak uygulanacak **patch** çıktısı görülüyor. Öyleyse bunu bir patch dosyası olarak kaydedebiliriz.

```bash
eaydin@dixon ~/calisma $ diff -u test.txt test2.txt > test1-2.patch
```

Şimdi patch dosyasını kullanabiliriz. Dosyanın içeriğinde patch'ın uygulanacağı dosya isimleri de belirtildiği için, doğrudan patch dosyasını programa standart girdi olarak vermemiz yeterli olacaktır.

```bash
eaydin@dixon ~/calisma $ patch < test1-2.patch 
patching file test.txt
eaydin@dixon ~/calisma $ cat test.txt 
birinci satir
ikinci baska satir
eaydin@dixon ~/calisma $ cat test2.txt 
birinci satir
ikinci baska satir
```

Gördüğünüz gibi artık `test.txt` dosyasının içeriği, `test2.txt` dosyasının içeriği ile aynı oldu.

**Patch'i Geri Alma:**

Uygulanan bir patch'i geri almak için `patch` komutuna `-R` (reverse) parametresi verilebilir:

```bash
eaydin@dixon ~/calisma $ patch -R < test1-2.patch 
patching file test.txt
eaydin@dixon ~/calisma $ cat test.txt 
birinci satir
ikinci satir
ucuncu satir
```

Bu komut, `test.txt` dosyasını patch uygulanmadan önceki orijinal haline geri döndürür. `diff` ve `patch` komutları, özellikle yazılım geliştirme süreçlerinde kod değişikliklerini paylaşmak ve uygulamak için yaygın olarak kullanılır.


# xargs

xargs komutu ile bir komuttan gelen standart çıktıyı başka bir komuta argüman olarak yönlendirebilirsiniz.

Örneğin bir dizindeki (ve alt dizinlerindeki) Python dosyalarının kaçar satırdan oluştuğunu görmek istersek

```bash
eaydin@dixon ~/devel/gkmv1 $ find . -name "*.py" | xargs wc -l
   697 ./cardread.py
    83 ./checkcronjobs.py
   637 ./GKM/commands.py
    91 ./GKM/communication.py
    47 ./GKM/crc8dallas.py
    33 ./GKM/database.py
   165 ./GKM/ethernet.py
    47 ./GKM/log.py
    62 ./GKM/messaging.py
    43 ./GKM/queue.py
    61 ./GKM/readconfig.py
    86 ./GKM/serialupdate.py
   132 ./GKM/wiegand.py
     0 ./GKM/__init__.py
   152 ./listener.py
    23 ./resetfoodgkm.py
    53 ./tools/gkm-watchdog.py
   867 ./tools/kontrol.py
  3279 total
```

Gördüğünüz gibi burada sondaki satır **total** değerini veriyor, Bu aslında `wc` programının bir özelliği, en sonda kendisine argüman olarak verilen bütün dosyaların satır sayılarının toplamını da verir. Örneğin şöyle bir kullanım yapsaydık da çalışacaktı, ama alt dizinleri aramayacaktı.

```bash
  eaydin@dixon ~/devel/gkmv1 $ wc -l *.py
  697 cardread.py
   83 checkcronjobs.py
  152 listener.py
   23 resetfoodgkm.py
  955 total
```

İçindeki boşluk karakteri geçen dosya isimlerinin kullanılabilmesi için **find** programı **-print0** argümanı ile çalıştırılmalı ve **xargs** programı ile **-0** argümanı kullanılmalıdır.

```bash
  find . -name "*.py" -print0 | xargs -0 wc -l
```

## Argümanların Farklı Yere Yerleştirilmesi

Farkındaysanız xargs'ın yaptığı, standart girdiden gelenleri ilgili komutun sonuna yerleştirmek oldu. Ancak bazı durumlarda gelenleri sona değil, başka bir yere yerleştirmek isteyebiliriz. Aşağıdaki örnek açıklayıcı olacaktır.

```bash
[root@test etc]# find /etc -maxdepth 1 -name "*.conf" -print0 | xargs -0 \
-I % echo Bulunan % dosyası
```

```
Bulunan /etc/libuser.conf dosyası
Bulunan /etc/host.conf dosyası
Bulunan /etc/yum.conf dosyası
Bulunan /etc/sudo.conf dosyası
Bulunan /etc/dracut.conf dosyası
Bulunan /etc/nsswitch.conf dosyası
Bulunan /etc/sudo-ldap.conf dosyası
Bulunan /etc/krb5.conf dosyası
Bulunan /etc/logrotate.conf dosyası
Bulunan /etc/cgrules.conf dosyası
Bulunan /etc/libaudit.conf dosyası
Bulunan /etc/resolv.conf dosyası
Bulunan /etc/ntp.conf dosyası
Bulunan /etc/mdadm.conf dosyası
Bulunan /etc/cgconfig.conf dosyası
Bulunan /etc/mke2fs.conf dosyası
Bulunan /etc/ld.so.conf dosyası
Bulunan /etc/rsyslog.conf dosyası
Bulunan /etc/gai.conf dosyası
Bulunan /etc/cgsnapshot_blacklist.conf dosyası
Bulunan /etc/sysctl.conf dosyası
Bulunan /etc/sestatus.conf dosyası
Bulunan /etc/grub.conf dosyası
```

Yukarıda **-I** argümanından sonra **%** kullandığımız için, komut içerisinde **%** görünen yere standart girdiden gelen konulacaktı. Örneğin **%** yerine **gelen** yazabilirdik.

```bash
[root@test etc]# find /etc -maxdepth 1 -name "*.conf" -print0 | xargs -0 \
-I gelen echo Bulunan gelen dosyası
```

## Argümanları Gruplandırmak

Bazı programlar bütün argümanları aldığında işe yaramazlar çünkü sınırlı sayıda argüman ile çalışırlar. Örneğin **diff** programı sadece iki dosya ismini argüman olarak alır ve bunları karşılaştırır. Öyleyse onlarca dosyayı diff ile kullanmak için, xargs'e argümanları gruplandırmasını söylememiz gerekir.

```bash
eaydin@dixon ~/calisma $ ls *.txt
test2.txt  test3.txt  test4.txt  test.txt
eaydin@dixon ~/calisma $ diff *.txt
diff: extra operand 'test4.txt'
diff: Try 'diff --help' for more information.
```

```bash
eaydin@dixon ~/calisma $ ls *.txt | xargs -L 2 diff
2a3,4
> ucuncu satir
> dorduncu satir
4,5d3
< dorduncu satir
< besinci satir
```

Yukarıdaki işlemin yaptığı, gelen ls çıktısını 2'li gruplar halinde diff programına sunmak olduk. Böylece diff önce test2.txt ve test3.txt dosyalarını karşılaştırıyor, ardından test4.txt ve test.txt dosyalarını karşılaştırıyor.

Benzer şekilde sadece çıktıyı gruplandırmak isteseydik, **-n** argümanını kullanabilirdik.

```bash
eaydin@dixon ~/calisma $ echo {0..9} | xargs -n 3
0 1 2
3 4 5
6 7 8
9
```

## Paralel Çalıştırma (`-P`)

`xargs`'ın güçlü özelliklerinden biri de, komutları paralel olarak çalıştırabilmesidir. `-P max-procs` seçeneği ile aynı anda kaç işlem çalıştırılacağı belirtilebilir. Bu, özellikle CPU-yoğun veya I/O-yoğun işlemleri çok sayıda dosya üzerinde yaparken performansı önemli ölçüde artırabilir.

Örneğin, bir dizindeki tüm `.jpg` dosyalarını `convert` komutuyla yeniden boyutlandırmak istediğimizi varsayalım. Bu işlem her dosya için ayrı ayrı zaman alacaktır. `xargs -P` ile bu işlemi paralel yapabiliriz:

```bash
# Aynı anda 4 işlem çalıştırarak tüm jpg dosyalarını 800x600 boyutuna getir
find . -name "*.jpg" -print0 | xargs -0 -P 4 -I {} convert {} -resize 800x600 resized/{} 
```

Burada `-P 4`, `xargs`'ın aynı anda en fazla 4 `convert` işlemi başlatacağını belirtir. Sistemdeki CPU çekirdek sayısına uygun bir değer seçmek genellikle iyi bir başlangıç noktasıdır.

## Maksimum Argüman Sayısı

Kabuk ortamınızda kullanabileceğiniz maksimum argüman sayısı sisteminize göre değişiklik gösterebilir. Aşağıdaki komutu yazarak öğrenebilirsiniz.

```bash
eaydin@dixon ~/calisma $ getconf ARG_MAX
2097152
```

Öte yandan xargs kendi limitlerine sahiptir. Bu limit normalde 4096 olarak belirlenmiştir ancak parametre kullanımıyla aşılabilir. **-s** parametersiyle bu limiti dilediğiniz sayıya (sistem limitleriniz dahilinde olmak şartıyla) çekebilirsiniz. Böylece, örneğin çok sayıda dosyanın bulunduğu dizinleri tararken limitlere takılmazsınız.

```bash
find / -path "/mnt/backup" -prune -o -iname "*.jpg" -o \
-iname "*.jpeg" -print0 | xargs -0 -s 2000000 -I % cp % /mnt/backup
```

Yukarıdaki komut, `/mnt/backup` dizini hariç bütün dizinlerde **jpg** ve **jpeg** uzantılı (büyük/küçük harf duyarsız) dosyaları `/mnt/backup` dizinine kopyalar.


# awk ve sed

GNU/Linux üzerinde **awk** ve **sed** ikilisi, standart girdi/çıktı işlemlerinde sıkça kullanılan, metin değişikliğine yarayan programlardır.

Her ne kadar her ikisi için de kompleks programlar yazılabiliyor olsa da, bu bölümde ana hatlarıyla nasıl kullanıldıklarını ve en sık işinize yarayacak yönlerini inceleyeceğiz.

## awk

awk çoğunlukla tablarla ayrılmış verilerin belirli sütununu almakta veya sırasını değiştirmekte kullanılır. Örneğin `ls -l` çıktısını ayıklamak için aşağıdaki yöntem kullanılabilir.

```bash
eaydin@dixon ~/calisma $ ls -l *.txt
-rw-r--r-- 1 eaydin eaydin 33 Nov 28 14:56 test2.txt
-rw-r--r-- 1 eaydin eaydin 55 Nov 28 13:49 test3.txt
-rw-r--r-- 1 eaydin eaydin 69 Nov 28 13:49 test4.txt
-rw-r--r-- 1 eaydin eaydin 33 Nov 28 15:01 test.txt
-rw-r--r-- 1 eaydin eaydin 33 Nov 28 15:00 yedek-test2.txt
-rw-r--r-- 1 eaydin eaydin 40 Nov 28 15:00 yedek-test.txt
eaydin@dixon ~/calisma $ ls -l *.txt | awk '{print "Dosya Adı: "$9" Boyut: "$5" kB"}'
Dosya Adı: test2.txt Boyut: 33 kB
Dosya Adı: test3.txt Boyut: 55 kB
Dosya Adı: test4.txt Boyut: 69 kB
Dosya Adı: test.txt Boyut: 33 kB
Dosya Adı: yedek-test2.txt Boyut: 33 kB
Dosya Adı: yedek-test.txt Boyut: 40 kB
```

Ayracı boşluk karakteri haricinde bir karakter olarak tanımlamak için **-F** argümanı kullanılır.

```bash
eaydin@dixon ~/calisma $ tail -n 5 /etc/passwd
saned:x:113:123::/home/saned:/bin/false
speech-dispatcher:x:114:29:Speech Dispatcher,,,:/var/run/speech-dispatcher:/bin/sh
eaydin:x:1000:1000:Emre,,,:/home/eaydin:/bin/bash
nvidia-persistenced:x:115:124:NVIDIA Persistence Daemon,,,:/:/sbin/nologin
sshd:x:116:65534::/var/run/sshd:/usr/sbin/nologin
eaydin@dixon ~/calisma $ tail -n 5 /etc/passwd | awk -F":" '{print "Kullanıcı: "$1}'
Kullanıcı: saned
Kullanıcı: speech-dispatcher
Kullanıcı: eaydin
Kullanıcı: nvidia-persistenced
Kullanıcı: sshd
```

Sitem üzerinde tanımlanmış değişkenleri alıp işleyebiliriz de.

```bash
eaydin@dixon ~/calisma $ X=10
eaydin@dixon ~/calisma $ echo $X
10
eaydin@dixon ~/calisma $ tail -n 5 /etc/passwd | \
awk -F":" -v val=$X '{print val " Kullanıcı: "$1}'
10 Kullanıcı: saned
10 Kullanıcı: speech-dispatcher
10 Kullanıcı: eaydin
10 Kullanıcı: nvidia-persistenced
10 Kullanıcı: sshd
eaydin@dixon ~/calisma $ tail -n 5 /etc/passwd | \
awk -F":" -v val=$X '{print val+1 " Kullanıcı: "$1;val=val+1}'
11 Kullanıcı: saned
12 Kullanıcı: speech-dispatcher
13 Kullanıcı: eaydin
14 Kullanıcı: nvidia-persistenced
15 Kullanıcı: sshd
```

Dosya içeriğindeki satırları etrafında tırnakla gösterebilmek için, şöyle teknikler kullanılabilir.

```bash
eaydin@dixon ~/calisma $ cat liste
PHP
Python
Ruby
Go
Perl
eaydin@dixon ~/calisma $ awk '{print q $0 q}' q="'" liste
'PHP'
'Python'
'Ruby'
'Go'
'Perl'
eaydin@dixon ~/calisma $ awk '{print q $0 q}' q='"' liste
"PHP"
"Python"
"Ruby"
"Go"
"Perl"
```

Aşağıdaki örnek, dosyayı okuyup ilk karaktere bakıyor, ilk karaker **P** ise bütün satırı yazdırıyor, değilse sadece ilk karakteri yazdırıyor.

```bash
eaydin@dixon ~/calisma $ awk '{ if(substr($0,0,1)=="P") {print $0} \
else { print substr($0,0,1)}}' liste
PHP
Python
R
G
Perl
```

**`awk` Dahili Değişkenler ve Bloklar:**

`awk` ayrıca birçok dahili değişkene sahiptir:

* `NR`: O an işlenen kaydın (genellikle satırın) numarası.
* `NF`: O an işlenen kayıttaki alan (field) sayısı.
* `$0`: Tüm satırın içeriği.

Ayrıca özel `BEGIN` ve `END` blokları bulunur:

* `BEGIN { ... }`: `awk` herhangi bir girdi satırını okumadan *önce* çalıştırılır. Başlık yazdırmak veya değişkenleri başlatmak için kullanılır.
* `END { ... }`: `awk` tüm girdi satırlarını okuduktan *sonra* çalıştırılır. Toplamları yazdırmak veya özet bilgi vermek için kullanılır.

Örnek:

```bash
# Dosyadaki her satırın numarasını ve alan sayısını yazdır, sonunda toplam satır sayısını belirt
awk '{ print "Satır No:", NR, "Alan Sayısı:", NF, $0 } END { print "Toplam Satır:", NR }' liste
```

## sed

sed dosyalar veya standart girdi üzerinde değişiklik yapmaya yarayan bir araçtır. Regular expression desteklediği gibi basit işlemler için de sıklıkla kullanılır. Örneğin yukarıda kullandığımız **liste** dosyasında içinde PHP geçen satırı **#** ile açıklama satırı haline getirmek isteseydik

```bash
eaydin@dixon ~/calisma $ sed '/PHP/s/^/#/' liste
#PHP
Python
Ruby
Go
Perl
```

Yukarıdaki komutun yaptığı işlem basittir. **liste** dosyası içinde **PHP** ifadesini saradı, **s** ile değişiklik yapılacağı bildirildi, **^** ile satırın başına **#** karakterinin ekleneceği ifade edildi.

Eğer bu satırı silmek isteseydik;

```bash
eaydin@dixon ~/calisma $ sed '/PHP/d' liste
Python
Ruby
Go
Perl
```

Eğer başında **P** geçen bütün satırları silmek isteseydik;

```bash
eaydin@dixon ~/calisma $ sed '/^P/d' liste
Ruby
Go
```

Çoğunlukla sed kullanımında **s** komutunu başta görürsünüz. Örneğin satırlarımızda **h** harflerini bulsak ve bu harften önce ve sonra **<** ile **>** işaretleri koymak istesek;

```bash
eaydin@dixon ~/calisma $ sed 's/[hH]/<&>/' liste 
P<H>P
Pyt<h>on
Ruby
Go
Perl
```

Öte yandan, sadece **h** harflerinin değil, içinde **h** harfi geçen satırın tamamını etiketlemek isteseydik,

```bash
eaydin@dixon ~/calisma $ sed 's/.*[hH].*/<&>/' liste 
<PHP>
<Python>
Ruby
Go
Perl
```

Gördüğünüz gibi bu örneklerde, bulduğumuz satırı ifade eden karakter **&** ile gösteriliyor.

**Global Değişiklik (`g` flagi):**

Varsayılan olarak, `sed`'in `s` komutu bir satırda bulduğu *ilk* eşleşmeyi değiştirir. Eğer satırdaki *tüm* eşleşmeleri değiştirmek istiyorsanız, komutun sonuna `g` (global) bayrağını eklemelisiniz:

```bash
# 'liste' dosyasındaki tüm 'P' harflerini 'X' ile değiştir
sed 's/P/X/g' liste 
```

**Yerinde Düzenleme (`-i` seçeneği):**

`sed` normalde sonucu standart çıktıya yazar, orijinal dosyayı değiştirmez. Değişiklikleri doğrudan orijinal dosyaya uygulamak için `-i` seçeneği kullanılır.

**DİKKAT:** `-i` seçeneği tehlikeli olabilir, çünkü orijinal dosyanın üzerine yazar. Yanlış bir komutla dosyanızı bozabilirsiniz. Kullanmadan önce komutunuzu test etmeniz veya bir yedek oluşturmanız şiddetle tavsiye edilir.

Bazı `sed` sürümleri, `-i` ile birlikte bir uzantı belirterek otomatik yedekleme yapmanıza olanak tanır:

```bash
# Değişiklikleri doğrudan 'liste' dosyasına uygula, orijinalini 'liste.bak' olarak yedekle
sed -i.bak 's/PHP/Hypertext Preprocessor/' liste 
```

Eğer yedek istemiyorsanız (ve dikkatliyseniz) sadece `-i` kullanabilirsiniz:

```bash
# Değişiklikleri doğrudan 'liste' dosyasına uygula (YEDEK YOK!)
# sed -i 's/PHP/Hypertext Preprocessor/' liste 
```

### Yaygın Sed Kullanımları

#### Boş Satırları Silme

Dosyamıza boş satırlar ekleyelim.

```bash
eaydin@dixon ~/calisma $ cat liste 


PHP
Python

Ruby
Go
Perl
```

Bu satırları silmek için aşağıdaki yöntem kullanılabilir,

```bash
eaydin@dixon ~/calisma $ sed '/^\s*$/d' liste
PHP
Python
Ruby
Go
Perl
```

#### Satır Öncesi Boşlukları Silme

```bash
eaydin@dixon ~/calisma $ cat liste
PHP
   Python
Ruby
Go
Perl
eaydin@dixon ~/calisma $ sed 's/^[ ]*//' liste
PHP
Python
Ruby
Go
Perl
```

#### Satır Sonrası Boşlukları Silme

```bash
eaydin@dixon ~/calisma $ sed 's/[ ]*$//' liste
```

#### Birden Fazla Boşluğu Tek Boşluk ile Değiştirme

```bash
eaydin@dixon ~/calisma $ cat liste
PHP
   Python
Ruby     .  
Go  Kolay    Öğrenilir
Perl
eaydin@dixon ~/calisma $ sed 's/  */ /g' liste
PHP
 Python
Ruby . 
Go Kolay Öğrenilir
Perl
```

#### Açıklama Satırı Ekleme

İçinde **o** veya **r** harfi geçen satırları **#** ile açıklama satırı haline getirelim.

```bash
eaydin@dixon ~/calisma $ sed -e '/[o|r]/s/^#*/#/' liste
PHP
#Python
Ruby  
#Go
#Perl
```

#### Açıklama Satırlarını Kaldırma

Dosyanızda açıklama satırları çok çeşitli hallerde olabilir, aşağıdaki örneği inceleyelim.

```bash
eaydin@dixon ~/calisma $ cat aciklama
PHP
#Python
#Python2
Ruby  
###Go
###Go2
# Perl
# Per2
  #C
  #C2
```

Burada hem başında boşluk olan satırlar var, hem birden fazla **#** ile başlayan satırlar var, hem de \*\*#\*\*den sonra boşluk içeren satırlar var. Tamamını *uncomment* edebilmek için aşağıdaki yöntem kullanılabilir.

```bash
eaydin@dixon ~/calisma $ sed 's/^[ ]*#*//' aciklama
PHP
Python
Python2
Ruby  
Go
Go2
 Perl
 Per2
C
C2
```

İçinde sadece **2** geçen satırların açıklamasını kaldırmak istersek,

```bash
eaydin@dixon ~/calisma $ sed 's/^[ ]*#*\(.*2\)/\1/' aciklama
PHP
#Python
Python2
Ruby  
###Go
Go2
# Perl
 Per2
  #C
C2
```

#### Satır Numaralandırma

`sed = dosyaismi` kullanımı, her satırı tek tek yazdırıp, öncesine satır numarasını yazdırır. Örneğin

```bash
eaydin@dixon ~/calisma $ sed = liste
1
PHP
2
Python
3
Ruby
4
Go
5
Perl
```

Öyleyse sed ile bu satırlarda  karakterlerini  ile değiştirip tablarla satırlarımızı gösterebiliriz.

```bash
eaydin@dixon ~/calisma $ sed = liste | sed 'N;s/\n/\t/'
1    PHP
2    Python
3    Ruby
4    Go
5    Perl
```

**Not:** Basit satır numaralandırma için genellikle `nl` veya `cat -n` komutları daha pratik olabilir:

```bash
nl liste
cat -n liste
```


# egrep ve Regular Expressions

Regular Expressions (Regex veya Düzenli İfadeler), metin içinde belirli kalıpları (pattern) aramak, eşleştirmek ve işlemek için kullanılan güçlü bir araçtır. Birçok programlama dili ve komut satırı aracı (örneğin `grep`, `sed`, `awk`, `perl`, `python`) regex desteği sunar.

`grep` (Global Regular Expression Print) komutu, dosyalarda veya standart girdide belirli bir kalıbı aramak için kullanılır. `grep`'in farklı sürümleri ve modları vardır:

* `grep`: Temel regex sözdizimini kullanır. Bazı özel karakterler (`+`, `?`, `|`, `()`, `{}`) anlamlarını yitirir ve kullanılacaksa `\` ile kaçış (escape) yapılması gerekir (örn. `\+`, `\(...\)`).
* `egrep` veya `grep -E`: Genişletilmiş regex (Extended Regular Expressions - ERE) sözdizimini kullanır. `+`, `?`, `|`, `()`, `{}` gibi karakterler özel anlamlarını korur ve kaçış yapmaya gerek kalmaz. Bu genellikle daha kullanışlıdır.
* `fgrep` veya `grep -F`: Sabit dizgeler (Fixed strings) arar, regex metakarakterlerini yorumlamaz. Basit metin aramaları için daha hızlı olabilir.

Bu bölümde `grep -E` (veya eşdeğeri `egrep`) ve genişletilmiş regex sözdizimine odaklanacağız.

## Temel Regex Metakarakterleri

Regex'te bazı karakterlerin özel anlamları vardır (metakarakterler):

* **.** (Nokta): Herhangi *tek bir* karakterle eşleşir (yeni satır karakteri hariç).
  * Örnek: `gr.p` ifadesi "grep", "grip", "grap" gibi dizgelerle eşleşir.
* **\*** (Yıldız): Kendinden *önceki* karakterin veya grubun **sıfır veya daha fazla** kez tekrarlanmasıyla eşleşir.
  * Örnek: `a*b` ifadesi "b", "ab", "aab", "aaab" ile eşleşir. `.*` ise herhangi bir karakter dizisiyle (boş dizgi dahil) eşleşir.
* **+** (Artı): Kendinden *önceki* karakterin veya grubun **bir veya daha fazla** kez tekrarlanmasıyla eşleşir. (`grep -E` gerektirir).
  * Örnek: `a+b` ifadesi "ab", "aab", "aaab" ile eşleşir, ancak sadece "b" ile eşleşmez.
* **?** (Soru İşareti): Kendinden *önceki* karakterin veya grubun **sıfır veya bir** kez tekrarlanmasıyla eşleşir. (`grep -E` gerektirir).
  * Örnek: `colou?r` ifadesi hem "color" hem de "colour" ile eşleşir.
* **^** (Şapka): Satırın *başlangıcıyla* eşleşir.
  * Örnek: `^Merhaba` ifadesi sadece satırın başında "Merhaba" ile başlayanlarla eşleşir.
* **$** (Dolar): Satırın *sonuyla* eşleşir.
  * Örnek: `dünya$` ifadesi sadece satırın sonunda "dünya" ile bitenlerle eşleşir. `^Merhaba dünya$` ise sadece "Merhaba dünya" içeren satırla eşleşir.

## Karakter Sınıfları ve Köşeli Parantezler `[...]`

* **`[abc]`**: Köşeli parantez içindeki karakterlerden *herhangi biriyle* eşleşir (bu örnekte 'a', 'b' veya 'c').
  * Örnek: `gr[ae]y` ifadesi "gray" ve "grey" ile eşleşir.
* **`[a-z]`**: Belirtilen aralıktaki karakterlerden *herhangi biriyle* eşleşir (bu örnekte herhangi bir küçük harf). `[0-9]` rakamlarla, `[a-zA-Z0-9]` alfanümerik karakterlerle eşleşir.
* **`[^abc]`**: Köşeli parantez içindeki `^` karakteri, parantez içindeki karakterler *dışındaki* herhangi bir karakterle eşleşir (bu örnekte 'a', 'b' ve 'c' olmayan herhangi bir karakter).

**POSIX Karakter Sınıfları:** Taşınabilirlik ve farklı yerel ayarlar (locale) için önceden tanımlanmış karakter sınıfları kullanılır (genellikle çift köşeli parantez içinde):

* `[[:digit:]]`: Rakamlar (`[0-9]`)
* `[[:lower:]]`: Küçük harfler (`[a-z]`)
* `[[:upper:]]`: Büyük harfler (`[A-Z]`)
* `[[:alpha:]]`: Harfler (`[a-zA-Z]`)
* `[[:alnum:]]`: Alfanümerik karakterler (`[a-zA-Z0-9]`)
* `[[:space:]]`: Boşluk karakterleri (boşluk, tab, yeni satır vb.)
* `[[:punct:]]`: Noktalama işaretleri
* `[[:xdigit:]]`: Hexadecimal rakamlar (`[0-9a-fA-F]`)

## Gruplama `(...)` ve Alternatif `|`

* **`(...)`**: Parantezler, bir grup karakteri veya alt ifadeyi bir arada tutmak için kullanılır. Quantifier'lar (`*`, `+`, `?`) veya alternatif (`|`) bu gruplara uygulanabilir. (`grep -E` gerektirir).
  * Örnek: `(ab)+` ifadesi "ab", "abab", "ababab" ile eşleşir.
* **`|`**: "Veya" anlamına gelir. İki veya daha fazla alternatiften biriyle eşleşir. (`grep -E` gerektirir).
  * Örnek: `kedi|köpek` ifadesi "kedi" veya "köpek" ile eşleşir. `^(kedi|köpek)` satır başında "kedi" veya "köpek" ile eşleşir.

## Quantifier'lar `{...}`

Belirli sayıda tekrarı belirtmek için kullanılır. (`grep -E` gerektirir).

* **`{n}`**: Önceki öğenin tam olarak `n` kez tekrarlanmasıyla eşleşir.
  * Örnek: `[0-9]{3}` tam olarak 3 rakamla eşleşir.
* **`{n,}`**: Önceki öğenin en az `n` kez tekrarlanmasıyla eşleşir.
  * Örnek: `[0-9]{2,}` en az 2 rakamla eşleşir.
* **`{n,m}`**: Önceki öğenin en az `n`, en fazla `m` kez tekrarlanmasıyla eşleşir.
  * Örnek: `[a-z]{3,5}` 3 ila 5 küçük harfle eşleşir.

## Kaçış Karakteri `\`

Bir metakarakterin özel anlamını kaldırıp normal bir karakter gibi eşleşmesini sağlamak için kullanılır.

* Örnek: `\.` ifadesi `.` metakarakteri yerine gerçekten nokta karakteriyle eşleşir. `\*` yıldız karakteriyle eşleşir. `\\` ters eğik çizgi karakteriyle eşleşir.

## `grep -E` (egrep) Kullanım Örnekleri

```bash
# dosya.txt içinde "hata" veya "uyarı" kelimelerini içeren satırları bul (büyük/küçük harf duyarsız)
grep -Ei 'hata|uyarı' dosya.txt

# dosya.txt içinde en az 5 rakamdan oluşan sayıları içeren satırları bul
grep -E '[0-9]{5,}' dosya.txt

# dosya.txt içinde IP adresine benzeyen kalıpları bul (basit örnek)
# (Not: Bu regex tüm geçerli IP adreslerini tam olarak kapsamaz)
grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' dosya.txt

# /etc/passwd dosyasında bash veya sh kabuğunu kullanan kullanıcıları bul
grep -E '(/bin/bash|/bin/sh)$' /etc/passwd

# Sadece eşleşen IP adreslerini göster (-o)
grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' access.log

# "TODO" içermeyen (-v) satırları göster
grep -Ev 'TODO' kod.py 
```

## Diğer `grep` Seçenekleri

* `-i`: Büyük/küçük harf ayrımını yok say (ignore case).
* `-v`: Eşleşmeyen satırları göster (invert match).
* `-c`: Eşleşen satır sayısını göster (count).
* `-l`: Eşleşme içeren dosyaların sadece isimlerini listele.
* `-L`: Eşleşme içermeyen dosyaların sadece isimlerini listele.
* `-n`: Eşleşen satırların satır numaralarını göster.
* `-r` veya `-R`: Dizinin içindeki alt dizinlerde de arama yap (recursive).
* `-o`: Sadece eşleşen metin kısmını göster, tüm satırı değil.
* `-A num`: Eşleşen satırdan sonraki `num` satırı da göster (After).
* `-B num`: Eşleşen satırdan önceki `num` satırı da göster (Before).
* `-C num`: Eşleşen satırın etrafındaki `num` satırı da göster (Context).

Regular expressions, pratik yaparak ve farklı araçlarda deneyerek öğrenilen güçlü bir yetenektir. İnternette birçok regex test aracı ve öğretici kaynak bulunmaktadır.


# rename

Aslında GNU/Linux sistemlerde dosyayı yeniden adlandırmak için bir komut bulunmaz. Bir dosyayı yeniden adlandırmak, onu taşımak demektir, dolayısıyla **mv** komutu bu iş için kullanılır.

`rename` ise genellikle Larry Wall tarafından yazılan bir Perl betiğidir (script) ve Perl'in güçlü düzenli ifade (regular expression) yeteneklerini kullanarak karmaşık toplu yeniden isimlendirme işlemleri için kullanılır. `mv` komutu ile ancak döngüler veya karmaşık betikler yazılarak yapılabilecek işlemler, `rename` ile tek satırda çözülebilir.

**Önemli Not: İki Farklı `rename` Komutu**

Linux sistemlerinde yaygın olarak iki farklı `rename` komutu bulunabilir:

1. **Perl `rename` (prename):** Bu bölümde anlatılan, Perl ifadesi kullanan güçlü versiyon. Paket yöneticilerinde adı `rename`, `prename` veya `perl-rename` olabilir.
2. **`util-linux`** **`rename`:** Daha basit bir komuttur ve sadece metin dizgisi değiştirme işlemi yapar (`rename 'eski_metin' 'yeni_metin' dosya...`).

Hangi versiyonun sisteminizde `rename` olarak çalıştığını anlamak için `man rename` komutuna bakabilirsiniz. Eğer man sayfası Perl ifadelerinden bahsediyorsa, bu bölümde anlatılan versiyondur. Bu kitapta Perl `rename` komutunu ele alacağız. Sisteminizde kurulu değilse, paket yöneticinizle (`sudo apt install rename` veya `sudo dnf install prename` gibi) kurabilirsiniz.

Örneğin, elimizde rakamlardan oluşan jpg dosyaları olsun, ve bu dosyaların uzantılarına dokunmadan, başına sonuna kelime eklemek isteyelim.

```bash
eaydin@dixon ~/calisma/jpg $ ls
0145.jpg  0146.jpg  3.jpg  897653.jpg
eaydin@dixon ~/calisma/jpg $ rename -v 's/(\d*)\.jpg$/goruntu_$1_dosyasi\.jpg/' *.jpg
0145.jpg renamed as goruntu_0145_dosyasi.jpg
0146.jpg renamed as goruntu_0146_dosyasi.jpg
3.jpg renamed as goruntu_3_dosyasi.jpg
897653.jpg renamed as goruntu_897653_dosyasi.jpg
eaydin@dixon ~/calisma/jpg $ ls
goruntu_0145_dosyasi.jpg  goruntu_0146_dosyasi.jpg  goruntu_3_dosyasi.jpg  goruntu_897653_dosyasi.jpg
```

Eğer işlemi geri almak isteseydik, yani başında **kelime\_** ve sonunda **\_başkakelime** olup ortasında rakam bulunan jpg dosyalarını **rakam.jpg** şeklinde değiştirmek isteseydik,

```bash
eaydin@dixon ~/calisma/jpg $ rename -v 's/.*_(\d*)_.*(\.jpg)$/$1$2/' *.jpg
goruntu_0145_dosyasi.jpg renamed as 0145.jpg
goruntu_0146_dosyasi.jpg renamed as 0146.jpg
goruntu_3_dosyasi.jpg renamed as 3.jpg
goruntu_897653_dosyasi.jpg renamed as 897653.jpg
eaydin@dixon ~/calisma/jpg $ ls
0145.jpg  0146.jpg  3.jpg  897653.jpg
```

Sonuçlarınızı test etmek için, öncesinde **-n** parametresini kullanabilirsiniz. Örneğin dosya adlarını büyük/küçük harf ile değiştirmek isteseydik,

```bash
eaydin@dixon ~/calisma/jpg $ ls
0145.jpg  0146.jpg  3.jpg  897653.jpg
eaydin@dixon ~/calisma/jpg $ rename -n 'y/a-z/A-Z/' *
0145.jpg renamed as 0145.JPG
0146.jpg renamed as 0146.JPG
3.jpg renamed as 3.JPG
897653.jpg renamed as 897653.JPG
eaydin@dixon ~/calisma/jpg $ ls
0145.jpg  0146.jpg  3.jpg  897653.jpg
eaydin@dixon ~/calisma/jpg $ rename -v 'y/a-z/A-Z/' *
0145.jpg renamed as 0145.JPG
0146.jpg renamed as 0146.JPG
3.jpg renamed as 3.JPG
897653.jpg renamed as 897653.JPG
eaydin@dixon ~/calisma/jpg $ ls
0145.JPG  0146.JPG  3.JPG  897653.JPG
```


# Imagemagick ve Görüntü Dosyaları

GNU/Linux komut satırında birden fazla görüntü dosyası üzerinde işlem yapmak için en uygun paketlerden birisi **ImageMagick** paketidir. İçerisinde `convert`, `mogrify`, `identify`, `composite`, `montage` gibi temel işlemleriniz için pek çok araç barındırır.

**Not:** ImageMagick'in modern sürümleri (versiyon 7 ve sonrası), genellikle tüm işlevleri tek bir `magick` komutu altında birleştirmiştir. Eski komutlar (`convert`, `identify` vb.) çoğu zaman geriye dönük uyumluluk için `magick` komutuna bir sembolik link olarak bulunur. Örneklerde eski komutlar kullanılsa da, bunların yerine `magick convert ...`, `magick identify ...` gibi kullanımların da mümkün olduğunu unutmayın. Örneğin:`convert logo.png logo.jpg` yerine `magick logo.png logo.jpgidentify logo.png` yerine `magick identify logo.png`

## Tip Dönüşümü

Örneğin dosya uzantılarından dosya tiplerini anlayacağı için, doğrudan png->jpg dönüşümü gibi işlemler yapabilirsiniz. Ayrıca kalite belirterek dosyanın kayıplı sıkıştırma miktarını belirleyebilirsiniz.

```bash
convert logo.png logo.jpg
convert logo.png -quality 70 logo.jpg
```

## Boyut Dönüşümü

Imagemagick ile dosya boyutlarını değiştirmek kolaydır.

```bash
convert logo.jpg -resize 300x120 logo.jpg
```

Yukarıdaki komut, görüntü oranını (aspect ratio) korur. Yani görüntüyü 300x120'lik bir dikdörtgen içerisine sığdırmaya çalışır. Eğer korumasını istemiyorsanız ve oran bozulsa bile tam olarak 300x120'lik çıktı elde etmek istiyorsanız bunu ünlem (!) koyarak belirtebilirsiniz.

```bash
convert logo.jpg -resize 300x120! logo.jpg
```

Tabii oran korunarak boyutlandırma için sadece genişlik (width) veya yükseklik (height) belirtebilirdik.

```bash
convert logo.jpg -resize 300 logo.jpg
convert logo.jpg -resize x120 logo.jpg
```

Ayrıca yüzde belirterek küçültme işlemleri de yapılabilir.

```bash
convert logo.jpg -resize 50% logo.jpg
```

### Sadece Küçült

Imagemagick ile sadece belirli boyuttan büyük olanları küçültmek için kullanılabilecek bir işaretçi var, büyüktür **>** işareti. Alışılmışın tersine bir gösterim ancak bunu şu şekilde okumak gerekir: "Sadece bu boyuttan **büyük** olan dosyalarda çalış".

```bash
convert logo.jpg -resize 128x128\> logo_thmb.jpg
```

### Sadece Büyüt

Yukarıdaki işlemin tam tersidir. Eğer dosya belirtilen limitlerden küçükse çalışır.

```bash
convert logo.jpg -resize 128x128\< logo_large.jpg
```

## Döndürme İşlemleri

Imagemagick ile görüntüyü döndürmek tahmin edileceği gibi **rotate** ile yapılır.

```bash
convert logo.jpg -rotate 90 logo.jpg
```

![Orijinal Görüntü](/files/-L9H1WGMl54bB28uF15Q)

![Döndürülen görüntü](/files/-L9H1WGOdgCHulCjwc5F)

*Kaynak:* <http://xkcd.com/1604/>

## Aynalama İşlemleri

Öte yandan aynalama işlemleri için **flip** ve **flop** seçenekleri kullanılır. **flip** görüntüyü başaşağı çevirir (x-ekseninde aynalama), **flop** ise soldan sağa doğru (y-ekseninde) çevirir.

```bash
eaydin@dixon ~/calisma/im $ convert 1604.png -flip flipped.png
eaydin@dixon ~/calisma/im $ convert 1604.png -flop flopped.png
eaydin@dixon ~/calisma/im $ convert 1604.png -flip -flop flipflop.png
```

![Orijinal görüntü](/files/-L9H1WGMl54bB28uF15Q)

![Flip edilmiş görüntü](/files/-L9H1WHwVnoqsnu6VdLH)

![Flop edilmiş görüntü](/files/-L9H1WHxxhpiOPNuXrxv)

![Hem Flip hem de Flop edilmiş görüntü](/files/-L9H1WHy3rVHHMAwZQXu)

## Filtreler

Programın bir çok filtresi bulunuyor. Tamamının üzerine geçmek bu kitabın amacının çok dışında olacaktır dolayısıyla sadece birkaç örnek ile sonuçlarını göstermek istedik.

```bash
eaydin@dixon ~/calisma/im $ convert 1604.png -radial-blur 20 blurred.png
```

![Radial Blur](/files/-L9H1WId1IckvvXkeQTP)

```bash
eaydin@dixon ~/calisma/im $ convert 1604.png -charcoal 4 charcoal.png
```

![Charcoal](/files/-L9H1WJ-kAbyqGom1fWy)

## Görüntü Hakkında Bilgi Almak

Yukarıdaki komutların tamamında birtakım işlemler yaptık ancak görüntü dosyası hakkında hiç bilgi almadık. Bunun için **identify** komutu kullanılabilir.

```bash
eaydin@dixon ~/calisma/im $ identify 1604.png 
1604.png PNG 177x205 177x205+0+0 8-bit DirectClass 32.9KB 0.000u 0:00.000
```

Dosya hakkında çok detaylı bilgi almak isterseniz **-verbose** seçeneğini kullanabilirsiniz. (Burada çıktıyı göstermiyoruz çünkü oldukça uzun)

```bash
identify -verbose 1604.png
```

## Watermark Eklemek

Görüntülere kaynağını belirten birtakım ifadeler ekleyebilirsiniz. Bu kısımda watermarking yöntemlerini inceleyeceğiz.

En kolay yöntem, pek çok internet sitesinde gördüğünüz gibi, görüntünün köşesine bir not eklemektir.

```bash
eaydin@dixon ~/calisma/im $ composite label:"xkcd.com" 1604.png labelled.png
```

![](/files/-L9H1WKGWJYK4F8QJQbI)

Öte yandan etiketimizi görüntünün altına yayılacak şekilde yerleştirebilirdik.

```bash
eaydin@dixon ~/calisma/im $ convert 1604.png -background Green \
label:'xkcd.com' -gravity center -append center-labelled.png
```

![](/files/-L9H1WKpZqQKo2cCnyS3)

**gravity** seçeneğini daha farklı biçimde kullanabilirdik.

```bash
eaydin@dixon ~/calisma/im $ convert 1604.png -pointsize 20 -draw "gravity east \
fill blue text 5,12 'xkcd' " east_wm1.png
eaydin@dixon ~/calisma/im $ convert 1604.png -pointsize 20 -draw "gravity east \
fill blue text 5,12 'xkcd' \
fill white text 6,11 'xkcd'  " east_wm2.png
```

![](/files/-L9H1WLkVLivHUJUTUjs)

![](/files/-L9H1WLlpK0bTb7zrr7T)

Daha şık bir sonuç elde etmek için, önce görüntünün enini bir değişkende saklıyoruz, ardından saydam bir katmanla watermark'ımızı ekliyoruz.

```bash
eaydin@dixon ~/calisma/im $ width=$(identify -format %w 1604.png)
eaydin@dixon ~/calisma/im $ echo $width
177
eaydin@dixon ~/calisma/im $ convert -background '#0008' -fill white \ 
-gravity center -size ${width}x30 caption:xkcd.com 1604.png +swap \ 
-gravity south -composite wm_trans.png
```

![](/files/-L9H1WMz0cTRuYzdo1-m)

Bir diğer seçenek, farklı bir görüntüyü orijinal görüntümüz ile karıştırıp watermark oluşturmaktır. Örneğin aşağıdaki penguen görüntüsü bizim imzamız olsun ve karikatürümüzün üzerine yerleştirmek isteyelim.

![](/files/-L9H1WNAn4D-OJ3hiaia)

Aşaıdaki gibi bir komutla bu görüntüyü orijinal görüntümüzle birleştirebiliriz.

```bash
eaydin@dixon ~/calisma/im $ composite -watermark 30% -gravity north \
-geometry +0+15 penguin.jpg 1604.png wm_pen.png
```

![](/files/-L9H1WNr4oFBfV4TWQEs)


# wget

Bu kitapçıkta daha önce de karşılaştığımız komutlardan **wget**, internetten dosya ve web sayfalarını indirmek için kullanılan güçlü ve esnek bir komut satırı aracıdır. İsmi **Web GET** sözcüklerinin kısaltmasıdır. Özellikle toplu indirmeler, yarım kalan indirmeleri devam ettirme ve web sitelerini yansıtma (mirroring) gibi işlemler için kullanışlıdır.

**`wget` vs `curl`:**`wget` ile benzer işlevleri gören bir diğer popüler araç `curl`'dür. İkisi de URL'lerden veri aktarımı yapar ancak farklı kullanım amaçları ve felsefeleri vardır:

* **`wget`:** Genellikle dosyaları indirmek ve web sitelerini özyinelemeli (recursive) olarak indirmek için tasarlanmıştır. Varsayılan olarak dosyaları diske kaydeder.
* **`curl`:** Daha çok tek bir URL ile etkileşim kurmak, veriyi standart çıktıya (stdout) yazdırmak (bu da pipe ile başka komutlara bağlanmasını kolaylaştırır) ve çok çeşitli protokolleri (HTTP, HTTPS, FTP, SCP, LDAP, SMTP vb.) desteklemek üzerine odaklanmıştır. API testleri ve betiklerde sıkça kullanılır.

Her iki aracın da kendine özgü güçlü yanları vardır ve genellikle sistem yöneticileri her ikisini de kullanır. Bu bölümde `wget`'e odaklanacağız.

İnternetten herhangi bir dosyayı indirmek için dosya adresini wget'e parametre olarak vermek yeterlidir.

```bash
wget http://www.plugged.in/downloads/plugged.sh
```

Yukarıdaki komutla bulunduğumuz dizine `plugged.sh` dosyası inecektir.

Bazen linkler istediğimiz isim yapısında olmayabilir. İndirilen dosyayı farklı isimle kaydetmek için aşağıdaki yöntem izlenebilir.

```bash
wget http://www.plugged.in/downloads/plugged.sh -O install.sh
```

Artık dosya `plugged.sh` ismiyle değil, `install.sh` ismiyle kaydedilecektir.

## Yarım Kalan İndirmeler

Normalde `wget` programı, indirilen dosya hali hazırda dizinde mevcutsa, yeni indirilen dosyayı sonuna **.1 .2** gibi rakamlar koyarak yazar. Örneğin yukarıdaki örnekte **plugged.sh** dosyası zaten dizinde mevcutsa, yeniden indirdiğimizde `wget` dosyayı **plugged.sh.1** olarak kaydeder.

Oysa indirme sırasında dosya yarım kalmışsa, kaldığı yerden devam ettirmek için **-c** parametresini vermemiz yeterlidir.

```bash
wget -c http://www.plugged.in/downloads/plugged.sh
```

## Hız Limitleme

İndirme hızını limitlemek için `--limit-rate` parametresi kullanılır.

```bash
wget --limit-rate=400k http://mirror.rackdc.com/CentOS/7/isos/x86_64/CentOS-7-x86_64-Minimal-1503-01.iso
```

## Deneme Sayısı

Bazı durumlarda indirme işlemini kaç kez deneyeceğinizi belirtmek isteyebilirsiniz.

```bash
wget --tries=10 http://plugged.in/downloads/plugged.sh
```

## İndirme İşlemini Arka Planda Gerçekleştirme

Büyük dosyaları indirme işlemini arka planda yürütebilirsiniz. Böyle bir durumda `wget` size programın PID numarasını verecek, ve logları yazdığı dosyayı bildirecekir. Bu sayede isterseniz indirme işlemini log dosyasından takip edebilir, dilediğiniz zaman PID numarasını kullanarak programı durdurabilirsiniz.

```bash
# wget -b http://mirror.rackdc.com/CentOS/7/isos/x86_64/CentOS-7-x86_64-Minimal-1503-01.iso
Continuing in background, pid 25965.
Output will be written to ‘wget-log’.
```

## Liste Kullanımı

İndirilecek dosyaların bir listesini bir program ile oluşturabilirsiniz, veya yükleme yazılımınızda kullanmak üzere hazırlayabilirsiniz. Bu listedeki linkleri sırayla indirmesi için **wget** programına parametre olarak verebilirsiniz.

```bash
eaydin@dixon ~/calisma/wget $ cat indir.txt
```

```
http://plugged.in/downloads/plugged.sh
http://mirror.rackdc.com/CentOS/7/isos/x86_64/CentOS-7-x86_64-Minimal-1503-01.iso
eaydin@dixon ~/calisma/wget $ wget -i indir.txt 
--2015-11-30 00:42:03--  http://plugged.in/downloads/plugged.sh
Resolving plugged.in (plugged.in)... 94.103.33.130, 2a00:7300:1::fff5
Connecting to plugged.in (plugged.in)|94.103.33.130|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 8990 (8,8K) [application/x-sh]
Saving to: ‘plugged.sh’

100%[===============================================================================================>] 8.990       --.-K/s   in 0,02s   

2015-11-30 00:42:05 (422 KB/s) - ‘plugged.sh’ saved [8990/8990]

--2015-11-30 00:42:05--  http://mirror.rackdc.com/CentOS/7/isos/x86_64/CentOS-7-x86_64-Minimal-1503-01.iso
Resolving mirror.rackdc.com (mirror.rackdc.com)... 94.103.32.100, 2a00:7300:1::100
Connecting to mirror.rackdc.com (mirror.rackdc.com)|94.103.32.100|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 666894336 (636M) [application/x-iso9660-image]
Saving to: ‘CentOS-7-x86_64-Minimal-1503-01.iso’

 0% [                                                                                                ] 531.035      296KB/s
```

## İndirme Kontrolü

Bazı durumlarda indirme işleminden önce indirmenin mümkün olup olmadığını kontrol edebilirsiniz. Bunun için `--spider` seçeneği kullanılabilir. Bu seçeneğin en yaygın kullanımı, sisteminizin internet erişiminin olup olmadığı, internet erişimi varsa da DNS çözümlemelerini doğru yapıp yapmadığınız konusundadır. Aşağıdaki örnekleri inceleyelim.

```bash
eaydin@dixon ~/calisma/wget $ wget --spider google.com
```

```
Spider mode enabled. Check if remote file exists.
--2015-11-30 00:26:28--  http://google.com/
Resolving google.com (google.com)... 216.58.209.14, 2a00:1450:4017:803::200e
Connecting to google.com (google.com)|216.58.209.14|:80... connected.
HTTP request sent, awaiting response... 302 Found
Location: http://www.google.com.tr/?gfe_rd=cr&ei=lHtbVtjnGcuz8wfWmI6IAw [following]
Spider mode enabled. Check if remote file exists.
--2015-11-30 00:26:28--  http://www.google.com.tr/?gfe_rd=cr&ei=lHtbVtjnGcuz8wfWmI6IAw
Resolving www.google.com.tr (www.google.com.tr)... 216.58.208.99, 2a00:1450:4017:803::2003
Connecting to www.google.com.tr (www.google.com.tr)|216.58.208.99|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Remote file exists and could contain further links,
but recursion is disabled -- not retrieving.
```

```bash
eaydin@dixon ~/calisma/wget $ echo $?
0
```

```bash
eaydin@dixon ~/calisma/wget $ wget --spider google.c
```

```
Spider mode enabled. Check if remote file exists.
--2015-11-30 00:26:52--  http://google.c/
Resolving google.c (google.c)... failed: Name or service not known.
wget: unable to resolve host address ‘google.c’
```

```bash
eaydin@dixon ~/calisma/wget $ echo $?
4
```

Gördüğünüz gibi **google.com** için **exit status 0** aldık, oysa **google.c** için **exit status 4** döndü. Bu sayede scriptlerimize bir internet kontrol mekanizması koyabiliriz.

En yaygın kullanım, bu seçeneği `-q` (quiet) seçeneği ile kullanmaktır.

```bash
eaydin@dixon ~/calisma/wget $ wget -q --spider google.com
eaydin@dixon ~/calisma/wget $ echo $?
0
```

**NOT:** Yukarıdaki ifadelerde **$?** gösteriminin ne anlama geldiğini bilmiyorsanız, kitabın Bash Programlama bölümüne bakabilirsiniz.

## Tarayıcı Gibi Davranmak

İndirmek istediğiniz bazı linkler kaynağın bir tarayıcı gibi davranmasını isterler.\
Aşağıda bu tip senaryolarda kullanabileceğiniz iki yol gösterici örnek görebilrsiniz.

```bash
# wget --user-agent="Mozilla/5.0 (X11; U; Linux i686; \ 
en-US; rv:1.9.0.3) Gecko/2008092416 \
Firefox/3.0.3" http://indirilecek-link
```

Veya cookie kullanılarak login yapılabilir.

```bash
# wget --save-cookies cookies.txt \
--post-data 'user=kullanici&password=sifre' \
http://sayfa.com/login.php

# wget --load-cookies cookies.txt http://sayfa.com/indir.tar.gz
```

## Sayfayı Tamamen İndirmek

```bash
wget --mirror -p --convert-links -P indirme_dizini http://plugged.in
```

Yukarıdaki komut [plugged.in](http://plugged.in) sayfasını `indirme_dizini` dizinine indirecektir. `--mirror` seçeneği, bütün dizinleri indirmesi gerektiğini belirtir. `-p` ile HTML'in doğru görüntülenmesi için gerekli dosyalar (örn. CSS dosyaları) beraberinde gelir. `--convert-links` HTML dosyaları içerisindeki linkleri yerel linkler ile değiştirir. Bu işlem sadece indirme tamamlanınca gerçekleşir, yani indirme işlemini yarıda keserseniz linkleri düzenlemez.

Yukarıdaki komutun açık hali şöyledir

```bash
wget --mirror --page-requisites --convert-links \
--directory-prefix=indirme_dizini http://plugged.in
```

Okuduğunuz kitabın HTML halini indirmek isterseniz aşağıdaki komutu kullanabilirsiniz.

```bash
wget --mirror --page-requisites --convert-links \
--directory-prefix=kitap \
https://veriteknik.gitbooks.io/linux-yonetimi/content/
```

## Belirli Dosya Tiplerini ve Dizin Oluşumunu Engellemek

Aşağıdaki örnek, rackdc CentOS mirror'undan iso dosyaları hariç (`--reject`) tüm dosyaları indirecek, ancak "Parent Directory"e gidip tarama işlemini genişletmeyecek (`-np`) ve tamamını tek dizine indirip alt dizinleri oluşturmayacaktır.

```bash
wget --reject=iso -P CentOS --mirror -np \ 
--no-directories http://mirror.rackdc.com/CentOS/7/isos/x86_64/
```

## Sadece Belirli Dosyaları İndirmek

Benzer şekilde sadece belirli tipteki dosyaları indirebilirsiniz.

```bash
wget -A.torrent -P torrent-files --mirror \
-np --no-directories \
http://mirror.rackdc.com/CentOS/7/isos/x86_64/
```

## FTP Kullanımı

Son olarak wget ile anonim ve şifreli FTP kullanımı göreceğiz.

```bash
# wget ftp-sitesi.com
# wget --ftp-user=KULLANICI --ftp-password=SIFRE ftp-sitesi.com
```

\*FreeBSD Sisteminde wget yerine fetch kullanılmaktadır.


# Python ile Dosya Sunuculuğu

Eğer dosya transferi yapmak istediğiniz tarafın teknik araçlara erişimi yetersizse, birden fazla kişiye dosya sunmak isterseniz, dosyayı alacak kişilerin sadece internet tarayıcısı kullanarak sunucunuz üzerindeki herhangi bir klasöre erişmelerini sağlayabilirsiniz.

Bunun için Python'dan faydalanacak olmamıza rağmen, derinlemesine Python bilgisine ihtiyaç yoktur. Python'un kendi içinde gelen basit bir HTTP sunucu modülü bulunur.

**Python 3 (Önerilen):**

Modern sistemlerde genellikle Python 3 kurulu gelir. Python 3'te bu modül `http.server` olarak adlandırılır. Örneğin `/root/resimler` dizinini (ve alt dizinlerini) HTTP üzerinden sunmak için, ilgili dizine gidip aşağıdaki komutu çalıştırmak yeterlidir:

```bash
[root@emre ~]# cd /root/resimler
[root@emre resimler]# python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
```

(Eğer sisteminizde `python3` yerine sadece `python` komutu Python 3'ü çalıştırıyorsa, `python -m http.server` kullanın.)

**Python 2 (Eski Sistemler):**

Python 2 (artık desteklenmiyor) kullanan eski sistemlerde ise modül adı `SimpleHTTPServer` idi:

```bash
[root@emre ~]# cd /root/resimler
[root@emre resimler]# python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...
```

Her iki durumda da, sunucunun çalıştığı makinenin IP adresine ve varsayılan olarak 8000 numaralı porta bir web tarayıcısı ile bağlanarak dizin içeriğine erişilebilir (örneğin, `http://SUNUCU_IP_ADRESI:8000`).

![](/files/-L9H1SD6mO8lNMoH0YyI)

Eğer 8000 dışında farklı bir port kullanmak isterseniz, port numarasını komutun sonuna ekleyebilirsiniz:

```bash
# Python 3
[root@emre resimler]# python3 -m http.server 9001
Serving HTTP on 0.0.0.0 port 9001 (http://0.0.0.0:9001/) ...

# Python 2
[root@emre resimler]# python -m SimpleHTTPServer 9001
Serving HTTP on 0.0.0.0 port 9001 ...
```

**Güvenlik Uyarısı:** Bu basit HTTP sunucusu, herhangi bir kimlik doğrulama veya güvenlik önlemi sunmaz. Sadece güvenli ağlarda, geçici dosya paylaşımları için kullanılmalıdır. Hassas verileri bu yöntemle paylaşmaktan kaçının.

Kopyalama işlemleri tamamlandıktan sonra, güvenlik gereği Python programını öldürmeniz gerekecektir. Bunu ister **kill** ile, ister **CTRL+C** ile *interrupt* göndererek yapabilirsiniz.


# Temel Dağıtımlar

Sunucularda kullanılan temel dağıtımların (ve bazı masaüstü dağıtımlarının) paket yönetimi, ağ ayarları gibi temel yapılandırmaları bu bölümde anlatılmıştır. Kurulum süreçleri dağıtımdan dağıtıma değişmekle birlikte, kurulum sonrası temel yönetim adımları benzerlikler gösterir.

## Disk Bölümlendirme ve Biçimlendirme Üzerine Notlar

Linux kurulumu sırasında disk bölümlendirme (partitioning) ve dosya sistemi seçimi önemli adımlardır. Kesin kurallar olmamakla birlikte, yaygın yaklaşımlar ve dikkat edilmesi gerekenler şunlardır:

**Bölümlendirme Stratejileri:**

* **Basit:** En azından bir kök (`/`) bölümü ve bir takas (swap) alanı gereklidir. `/boot` bölümü, özellikle UEFI sistemlerde veya LVM/şifreleme kullanıldığında ayrı bir bölüm olarak oluşturulur (genellikle 500MB - 1GB yeterlidir).
* **Ayrı Bölümler:** Sunucunun kullanım amacına göre `/home` (kullanıcı verileri), `/var` (loglar, veritabanları, web içerikleri gibi değişken veriler), `/tmp` (geçici dosyalar) gibi dizinleri ayrı bölümlere ayırmak yönetimi kolaylaştırabilir ve bir bölümün dolmasının diğerlerini etkilemesini engelleyebilir.
* **LVM (Logical Volume Management):** Fiziksel diskleri veya bölümleri bir havuzda toplayıp, bu havuzdan mantıksal birimler (LV) oluşturmayı sağlar. Bölümleri sonradan yeniden boyutlandırma, anlık görüntü (snapshot) alma gibi esneklikler sunar. Sunucu ortamlarında sıklıkla tercih edilir.

**Takas Alanı (Swap):**

* RAM dolduğunda veya sistem askıya alma (hibernation) için kullanılır.
* Geleneksel olarak ayrı bir swap bölümü oluşturulurdu.
* Modern sistemlerde, özellikle LVM kullanılmıyorsa veya esneklik isteniyorsa, **swap dosyası** kullanmak daha yaygındır. Swap dosyasının boyutu sonradan daha kolay değiştirilebilir.
* **Boyut:** Eskiden "RAM x 2" kuralı yaygındı ancak modern sistemlerde (özellikle bol RAM olanlarda) bu genellikle gereksizdir. Gerekli swap miktarı iş yüküne bağlıdır. Genel bir başlangıç noktası:
  * Az RAM (< 4GB): RAM kadar veya biraz fazlası.
  * Orta RAM (4GB - 16GB): RAM kadar.
  * Çok RAM (> 16GB): RAM'in yarısı veya sabit bir miktar (örn. 4GB-8GB), eğer hibernation kullanılmayacaksa daha azı veya hiç olmayabilir.

**Dosya Sistemleri:**

* **ext4:** Uzun yıllardır varsayılan olan, kararlı, güvenilir ve yaygın olarak kullanılan günlük (journaling) dosya sistemidir. Çoğu durum için iyi bir tercihtir.
* **XFS:** Özellikle RHEL ve türevlerinde varsayılan olarak gelen, yüksek performanslı, büyük dosyalar ve dosya sistemleri için optimize edilmiş bir günlük dosya sistemidir. Paralel I/O işlemleri için iyidir.
* **Btrfs:** Modern, kopya-üzerine-yazma (copy-on-write) özellikli bir dosya sistemidir. Anlık görüntü (snapshot), alt birimler (subvolumes), dahili RAID benzeri özellikler sunar, ancak ext4 veya XFS kadar olgunlaşmış kabul edilmeyebilir.
* **ext2:** Günlük tutmayan (non-journaling) eski bir dosya sistemidir. Modern SSD'lerde journaling'in performans etkisi ve yıpranma endişeleri büyük ölçüde azaldığı için, **ext2 kullanımı genellikle önerilmez**. `ext4`'ün sunduğu veri bütünlüğü koruması (journaling sayesinde) genellikle daha önemlidir.

Seçim, dağıtımın varsayılanlarına, sunucunun iş yüküne ve sistem yöneticisinin tecrübesine bağlı olacaktır. Çoğu genel amaçlı sunucu için `ext4` veya `XFS` güvenli ve performanslı seçeneklerdir.


# RHEL Tabanlı (CentOS, Rocky, Alma)

Bu bölüm, Red Hat Enterprise Linux (RHEL) ekosistemindeki güncel dağıtımlara odaklanmaktadır. Eskiden çok popüler olan CentOS Linux, RHEL'in birebir ücretsiz bir kopyası olarak hizmet veriyordu. Ancak CentOS projesi, RHEL'in bir sonraki sürümünün geliştirme dalı olan **CentOS Stream**'e odaklanmıştır. CentOS Linux'un yerini doldurmak için ise topluluk tarafından **Rocky Linux** ve **AlmaLinux** gibi RHEL ile birebir uyumlu (bug-for-bug compatible) dağıtımlar geliştirilmiştir.

## Genel Özellikler

* **Köken:** Hepsi Red Hat Enterprise Linux (RHEL) kod tabanını temel alır. RHEL, kurumsal düzeyde destek ve uzun vadeli kararlılık sunan ticari bir üründür.
* **CentOS Stream:** RHEL'in bir sonraki küçük sürümüne (minor release) giden geliştirme adımlarını içerir. RHEL'den biraz daha ileride, güncel paketler sunar ancak RHEL klonları kadar uzun vadeli stabilite garantisi vermeyebilir. Geliştirme ve test ortamları için veya en son RHEL özelliklerine erken erişim isteyenler için uygundur.
* **Rocky Linux & AlmaLinux:** CentOS Linux'un misyonunu devralan, RHEL ile tam uyumluluk hedefleyen, topluluk destekli ücretsiz dağıtımlardır. Kararlı sunucu ortamları için tasarlanmışlardır ve RHEL ile aynı yaşam döngüsünü takip etmeyi hedeflerler.
* **Paket Yönetimi:** RPM paket formatını ve modern `dnf` paket yöneticisini kullanırlar (`yum` eski sürümlerde kullanılıyordu ve genellikle `dnf`'e bir sembolik linktir).
  * [RPM Paketleri](/temel-dagitimlar/centos/rpm-paketleri)
  * [DNF Paket Yöneticisi (yum yerine)](https://github.com/VeriTeknik/linux_kitap/blob/master/temel-dagitimlar/centos/yum-paket-yoeneticisi.md) (Dosya adı eski kalmış, içerik güncellenmeli)
* **Depo Yönetimi:** Yazılım depoları (repositories) `/etc/yum.repos.d/` dizini altındaki `.repo` dosyaları ile yönetilir.
  * [Repo Ayarları](/temel-dagitimlar/centos/repo-ayarlari)
* **Ağ Yönetimi:** Genellikle NetworkManager servisi ve `nmcli` komut satırı aracı veya `nmtui` metin arayüzü ile yönetilir. Eski `network` servisi ve `/etc/sysconfig/network-scripts/` altındaki `ifcfg-*` dosyaları hala kullanılabilir olsa da, NetworkManager modern standarttır.
  * [Network Ayarları](/temel-dagitimlar/centos/network-ayarlari)
* **Güvenlik:** SELinux (Security-Enhanced Linux) genellikle varsayılan olarak etkindir ve zorunlu erişim kontrolü (MAC) sağlar. Firewall yönetimi için `firewalld` kullanılır.
* **Hedef Kitle:** Kararlı sunucu ortamları, kurumsal uygulamalar, RHEL ekosistemiyle uyumluluk arayanlar. CentOS Stream daha çok geliştiricilere ve en son özellikleri test etmek isteyenlere yöneliktir.

**Kurulum:**\
Bu dağıtımların kurulumu genellikle Anaconda grafiksel veya metin tabanlı yükleyici ile yapılır. Kurulum adımları (dil, klavye, saat dilimi, disk bölümlendirme, ağ ayarları, yazılım seçimi, kullanıcı oluşturma) dağıtımlar arasında büyük ölçüde benzerlik gösterir. Detaylı kurulum kılavuzları için ilgili dağıtımın resmi belgelerine başvurulmalıdır:

* CentOS Stream: <https://www.centos.org/centos-stream/>
* Rocky Linux: <https://rockylinux.org/>
* AlmaLinux: <https://almalinux.org/>

Bu bölümdeki diğer dosyalar, bu modern RHEL tabanlı dağıtımlarda paket yönetimi, depo ayarları ve ağ yapılandırması gibi temel konuları ele alacaktır (içeriklerinin güncellenmesi gerekmektedir).


# rpm Paketleri

Red Hat için geliştirilmiş paket yönetim sistemidir. Paketler -çoğunlukla olduğu gibi- doğrudan derlenmiş dosyalar olarak dağıtılabileceği gibi, kaynak kodların dağıtımını (srpm, spm) da sağlayabilir.

RPM (RPM Package Manager, eskiden Red Hat Package Manager), RHEL tabanlı dağıtımların (CentOS Stream, Rocky Linux, AlmaLinux, Fedora vb.) kullandığı temel paket yönetim sistemidir. Paketler genellikle `.rpm` uzantılı dosyalardır ve derlenmiş programları, kütüphaneleri, yapılandırma dosyalarını ve kurulum/kaldırma betiklerini içerir. Kaynak kod paketleri ise `.src.rpm` uzantılıdır.

**Önemli Not:** `rpm` komutu, paketleri doğrudan yönetmek için kullanılan düşük seviyeli bir araçtır. **Bağımlılıkları otomatik olarak çözmez.** Bu nedenle, paket kurma, kaldırma veya güncelleme işlemleri için genellikle `dnf` (veya eski sistemlerde `yum`) gibi daha üst seviye paket yöneticilerinin kullanılması **şiddetle tavsiye edilir**. `rpm` komutu daha çok paketleri sorgulamak, dosyaların hangi pakete ait olduğunu bulmak veya bağımlılıkları manuel olarak yönetmek gerektiğinde kullanılır.

RPM paketlerinin isimlendirmesinde genellikle aşağıdaki düzen izlenir.

```
<name>-<version>-<release>.<architecture>.rpm
<isim>-<versiyon>-<dağıtım>.<mimari>.rpm
```

Çoğunlukla yukarıdaki bölümlerden **isim** ve **mimari** kısmı bizi ilgilendirecektir. **isim** kısmı, tahmin edeceğiniz üzere yüklemek istediğimiz pakettir. **mimari** ise çalıştığımız sistemin işlemci mimarisidir. Örneğin x86, i386, arm gibi değerler alabilir. noarch yazması, paketin mimari bağımsız olması demektir. Örneğin düz metin dosyaları, Python/Perl scriptleri bu şekilde olabilir.

rpm dosyalarını genellikle dağıtımınızın yapılandırılmış depolarından (`dnf` aracılığıyla) veya güvenilir üçüncü parti kaynaklardan edinebilirsiniz. İnternetten rastgele indirilen RPM paketlerini kurmak güvenlik riski oluşturabilir.

## `rpm` Komutu ile Sorgulama ve Yönetim

Aşağıda `rpm` komutunun bazı yaygın kullanım örnekleri verilmiştir. Unutmayın, kurulum/kaldırma/güncelleme için genellikle `dnf` tercih edilmelidir.

**Paket Kurulumu (Bağımlılıkları Çözmez!):**

İndirilmiş bir RPM dosyasını kurmak için (genellikle `-ivh` kullanılır: install, verbose, hash marks):

```bash
rpm -ivh paket-dosyası.rpm
```

**Not:** Eğer bu paket başka paketlere bağımlıysa ve bu bağımlılıklar sistemde kurulu değilse, `rpm` komutu hata verecektir. `dnf install paket-dosyası.rpm` komutu ise bağımlılıkları depolardan otomatik olarak bulup kurmaya çalışır.

**Paket Sorgulama:**

Bir RPM dosyasının (kurulu olmayan) bağımlı olduğu paketleri listelemek için (`-p` ile dosya üzerinde işlem yapılır):

```bash
rpm -qpR paket-dosyası.rpm
```

Bir RPM dosyasının (kurulu olmayan) içerdiği genel bilgileri görmek için:

```bash
rpm -qip paket-dosyası.rpm
```

Bir RPM dosyasının (kurulu olmayan) içerdiği dosyaları listelemek için:

```bash
rpm -qlp paket-dosyası.rpm
```

**Kurulu Paketleri Sorgulama:**

Sistemde belirli bir paketin kurulu olup olmadığını kontrol etmek için:

```bash
rpm -q htop
```

Sistemde kurulu tüm paketleri listelemek için (`less` ile kullanmak faydalıdır):

```bash
rpm -qa | less
```

Kurulu bir paket hakkında detaylı bilgi almak için:

```bash
rpm -qi nmap
```

Kurulu bir paketin içerdiği dosyaları listelemek için:

```bash
rpm -ql nmap
```

Belirli bir dosyanın hangi kurulu pakete ait olduğunu bulmak için:

```bash
rpm -qf /etc/my.cnf
```

Kurulu bir paketin dosyalarının bütünlüğünü doğrulamak için (değiştirilmiş, eksik dosyaları vb. kontrol eder):

```bash
rpm -V nmap
```

(Eğer komut çıktı vermezse, paket dosyaları orijinal durumdadır.)

**Paket Kurulum/Güncelleme/Kaldırma (Düşük Seviye):**

**Uyarı:** Aşağıdaki komutlar bağımlılıkları otomatik yönetmez. Genellikle `dnf` kullanın.

Bağımlılıkları göz ardı ederek paket kurmak (Genellikle önerilmez!):

```bash
rpm -ivh --nodeps paket-dosyası.rpm
```

Bir paketi güncellemek veya kurulu değilse kurmak için (`-U` update/install):

```bash
rpm -Uvh paket-dosyası.rpm
```

(Sadece kuruluysa güncellemek için `-F` veya `--freshen` kullanılır.)

Bir paketi kaldırmak için (`-e` erase):

```bash
rpm -e paket-ismi
```

**Not:** Bu komut, kaldırılan pakete bağımlı olan diğer paketlerin çalışmasını bozabilir. `dnf remove paket-ismi` komutu bağımlılıkları daha güvenli yönetir.

Bağımlılıkları kontrol etmeden bir paketi kaldırmak için (Genellikle önerilmez!):

```bash
rpm -ev --nodeps paket-ismi
```

Özetle, `rpm` komutu paketler hakkında bilgi almak ve düşük seviyeli işlemler yapmak için kullanışlıdır, ancak günlük paket yönetimi (kurulum, kaldırma, güncelleme) için `dnf` komutunu kullanmak daha güvenli ve pratiktir.


# DNF Paket Yöneticisi

RHEL tabanlı modern Linux dağıtımlarında (Fedora, CentOS Stream, Rocky Linux, AlmaLinux, RHEL 8+) paket yönetimi için kullanılan standart araç **dnf** (Dandified YUM)'dir. `dnf`, eski paket yöneticisi `yum`'un (Yellowdog Updater Modified) yeni nesil versiyonudur ve daha iyi performans, daha düşük bellek kullanımı, geliştirilmiş bağımlılık çözümü gibi avantajlar sunar.

Çoğu modern sistemde, geriye dönük uyumluluk için `yum` komutu `dnf`'e yönlendirilmiş bir sembolik link veya alias olabilir. Ancak, yeni komutları ve özellikleri kullanmak için doğrudan `dnf` komutunu öğrenmek ve kullanmak tavsiye edilir.

`dnf`, sisteminize yazılım kurmak, güncellemek, kaldırmak ve yapılandırılmış yazılım depolarını (repositories) yönetmek için kullanılır. Temel olarak RPM paketleri üzerinde çalışır ancak bağımlılıkları otomatik olarak çözer.

## Paket Arama ve Listeleme

Bir paketin depolarda mevcut olup olmadığını aramak için `search` kullanılır:

```bash
# İçinde 'htop' geçen paketleri ara
sudo dnf search htop 
```

Belirli bir paketin veya tüm paketlerin listelenmesi için `list` kullanılır:

```bash
# 'htop' paketinin kurulu olup olmadığını ve mevcut sürümünü listele
sudo dnf list htop

# Sistemde kurulu tüm paketleri listele
sudo dnf list installed | less

# Depolarda mevcut tüm paketleri listele
sudo dnf list available | less

# Tüm paketleri (kurulu ve mevcut) listele
sudo dnf list all | less 
```

Kurulu paketleri listelemek için `rpm -qa` komutu da kullanılabilir.

## Paket Kurma (`install`)

Bir veya daha fazla paketi kurmak için `install` komutu kullanılır. `dnf`, gerekli bağımlılıkları otomatik olarak bulup kurmaya çalışacaktır.

```bash
# htop paketini kur
sudo dnf install htop
```

Kurulum sırasında onay istenecektir. Onay vermeden doğrudan kurmak için `-y` parametresi eklenebilir:

```bash
sudo dnf install -y htop
```

Yerel bir RPM dosyasını kurarken de `dnf` kullanmak, bağımlılıkların depolardan çözülmesini sağlar:

```bash
sudo dnf install /path/to/local-package.rpm
```

## Paket Kaldırma (`remove`)

Bir veya daha fazla paketi kaldırmak için `remove` (veya `erase`) komutu kullanılır:

```bash
# htop paketini kaldır
sudo dnf remove htop
```

Yine onay istenir ve `-y` ile atlanabilir. `dnf remove`, kaldırılan pakete bağımlı olan ve başka hiçbir paket tarafından kullanılmayan diğer paketleri de kaldırmayı önerebilir (bkz. `autoremove`).

## Paket Güncelleme (`upgrade`)

Sistemdeki kurulu tüm paketleri en son sürümlerine güncellemek için `upgrade` komutu kullanılır:

```bash
# Tüm sistemi güncelle
sudo dnf upgrade -y
```

Sadece belirli bir paketi güncellemek için:

```bash
# Sadece vim paketini güncelle
sudo dnf upgrade vim
```

Sadece güvenlik güncellemelerini uygulamak için:

```bash
sudo dnf upgrade --security
```

Hangi paketlerin güncellemesinin mevcut olduğunu görmek için `check-update` kullanılır:

```bash
sudo dnf check-update
```

## Paket Bilgisi (`info`)

Bir paket hakkında (kurulu olsun veya olmasın) detaylı bilgi almak için `info` kullanılır:

```bash
sudo dnf info htop
```

Bu komut paketin sürümünü, mimarisini, boyutunu, özetini, açıklamasını ve hangi depodan geldiğini gösterir. Benzer bilgi `rpm -qi <paket-ismi>` ile de alınabilir (sadece kurulu paketler için).

## Dosyanın Hangi Pakete Ait Olduğunu Bulma (`provides`)

Belirli bir dosyanın veya komutun hangi paket tarafından sağlandığını bulmak için `provides` (veya `whatprovides`) kullanılır:

```bash
# /usr/bin/htop komutunu hangi paketin sağladığını bul
sudo dnf provides /usr/bin/htop

# httpd.conf dosyasını sağlayan paketi bul
sudo dnf provides '*/httpd.conf' 
```

## Paket Grupları (`group`)

İlgili paketler genellikle gruplar halinde sunulur (örneğin, "Web Server", "Development Tools").

Mevcut grupları listelemek için:

```bash
sudo dnf group list
sudo dnf group list hidden # Gizli grupları da göster
```

Bir grup hakkında bilgi almak için (içerdiği zorunlu, varsayılan, opsiyonel paketler):

```bash
sudo dnf group info "Development Tools"
```

Bir grubu kurmak, güncellemek veya kaldırmak için:

```bash
sudo dnf group install "Development Tools"
sudo dnf group upgrade "Development Tools"
sudo dnf group remove "Development Tools"
```

Grup kurulumlarında varsayılan olarak hangi tür paketlerin (mandatory, default, optional) kurulacağını `/etc/dnf/dnf.conf` dosyasındaki `group_package_types` direktifi belirler.

## İşlem Geçmişi (`history`)

`dnf`, yapılan tüm kurulum, kaldırma, güncelleme işlemlerinin kaydını tutar. Bu, değişiklikleri takip etmek ve gerekirse geri almak için çok kullanışlıdır.

Geçmiş işlemleri listelemek için:

```bash
sudo dnf history list
```

Belirli bir işlem hakkında detaylı bilgi almak için (ID'si ile):

```bash
sudo dnf history info 15 
```

Belirli bir işlemi geri almak için (örneğin 15 numaralı kurulumu geri al):

```bash
sudo dnf history undo 15
```

Geri alınan bir işlemi tekrar uygulamak için:

```bash
sudo dnf history redo 15
```

## Diğer Kullanışlı `dnf` Komutları

* **`autoremove`**: Başka hiçbir kurulu paketin ihtiyaç duymadığı bağımlılıkları (artık gereksiz olan paketleri) kaldırmak için kullanılır. Genellikle bir `remove` işleminden sonra çalıştırılır.

  ```bash
  sudo dnf autoremove
  ```
* **`downgrade`**: Bir paketi önceki bir sürümüne düşürmek için kullanılır.

  ```bash
  sudo dnf downgrade <paket-ismi>
  ```
* **`reinstall`**: Bir paketi yeniden kurmak için kullanılır (yapılandırma dosyaları genellikle korunur).

  ```bash
  sudo dnf reinstall <paket-ismi>
  ```
* **`clean`**: `dnf` tarafından önbelleğe alınan verileri temizlemek için kullanılır (örn. `dnf clean all`).

## Modüller (RHEL 8+ / CentOS Stream 8+)

RHEL 8 ve sonrası tabanlı dağıtımlarda "Application Streams" (Uygulama Akışları) ve `dnf module` komutları tanıtılmıştır. Bu, aynı paketin farklı sürümlerini (örneğin Python 3.6, 3.8, 3.9) aynı anda depolarda bulundurmayı ve kullanıcının hangisini kuracağını seçmesini sağlar.

Mevcut modülleri listelemek için:

```bash
sudo dnf module list
```

Belirli bir modül akışını (stream) etkinleştirmek ve kurmak için:

```bash
sudo dnf module install <modül-adı>:<akış-adı> 
# Örnek: sudo dnf module install python39
```

## Yapılandırma

`dnf`'in ana yapılandırma dosyası `/etc/dnf/dnf.conf`'tur. Yazılım depoları ise `/etc/yum.repos.d/` dizini altındaki `.repo` uzantılı dosyalarda tanımlanır (bkz. [Repo Ayarları](/temel-dagitimlar/centos/repo-ayarlari)).

`dnf`, RHEL tabanlı sistemlerde paket yönetiminin temel taşıdır ve `rpm` komutuna göre çok daha kullanıcı dostu ve güvenli bir deneyim sunar.


# Repo Ayarları

`dnf` paket yöneticisi, RPM paketlerini **depo** (repository) adı verilen kaynaklardan indirir. Bu depolar, dağıtımın resmi paketlerini barındıran sunucular olabileceği gibi, üçüncü parti yazılımları veya güncel sürümleri içeren ek depolar da olabilir.

## Depo Yapılandırma Dosyaları (`.repo`)

Yazılım depoları, `/etc/yum.repos.d/` dizini altında bulunan `.repo` uzantılı metin dosyaları ile tanımlanır. Her bir `.repo` dosyası bir veya daha fazla depo bölümü içerebilir.

Bir depo bölümü genellikle aşağıdaki gibi görünür:

```ini
[repo-id]
name=Deponun Açıklayıcı Adı
baseurl=http://depo.sunucusu/yol/mimari/
# veya mirrorlist=http://ayna.listesi.sunucusu/?release=$releasever&arch=$basearch&repo=repo-id
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-repo-id
```

* **`[repo-id]`**: Depo için benzersiz bir kimlik (ID). Köşeli parantez içinde yazılır.
* **`name`**: Deponun insan tarafından okunabilir adı.
* **`baseurl`**: Deponun bulunduğu ana URL. Birden fazla `baseurl` satırı olabilir. `$releasever` (örn. 8, 9) ve `$basearch` (örn. x86\_64, aarch64) gibi değişkenler içerebilir.
* **`mirrorlist`**: `baseurl` yerine, coğrafi olarak en yakın veya en hızlı depoyu bulmak için kullanılan bir ayna listesi URL'si.
* **`enabled`**: Deponun aktif olup olmadığını belirtir (`1` aktif, `0` pasif).
* **`gpgcheck`**: Paketlerin GPG imzalarının kontrol edilip edilmeyeceğini belirtir (`1` evet, `0` hayır). Güvenlik için genellikle `1` olması önerilir.
* **`gpgkey`**: Paketleri doğrulamak için kullanılacak GPG anahtarının URL'si veya dosya yolu. `gpgcheck=1` ise bu gereklidir.

## Depoları Listeleme ve Yönetme

**Aktif Depoları Listeleme:**\
Sistemde tanımlı ve aktif (enabled) olan depoları listelemek için:

```bash
sudo dnf repolist
```

**Tüm Depoları Listeleme (Aktif ve Pasif):**

```bash
sudo dnf repolist all
```

**Depoları Etkinleştirme/Devre Dışı Bırakma (Geçici - Komut Bazında):**\
Bir `dnf` komutunu çalıştırırken belirli depoları geçici olarak etkinleştirmek veya devre dışı bırakmak için `--enablerepo` ve `--disablerepo` seçenekleri kullanılır:

```bash
# epel deposunu geçici olarak etkinleştirerek zmap paketini ara
sudo dnf --enablerepo=epel search zmap

# base ve updates dışındaki tüm depoları devre dışı bırakarak sadece bu depolardaki paketleri listele
sudo dnf --disablerepo="*" --enablerepo="base,updates" list available 
```

**Depoları Etkinleştirme/Devre Dışı Bırakma (Kalıcı - `dnf config-manager`):**`dnf-plugins-core` paketi ile gelen `dnf config-manager` aracı, depoları kalıcı olarak yönetmek için kolay bir yol sunar (eğer kurulu değilse `sudo dnf install dnf-plugins-core` ile kurun):

```bash
# epel deposunu kalıcı olarak etkinleştir
sudo dnf config-manager --set-enabled epel

# epel deposunu kalıcı olarak devre dışı bırak
sudo dnf config-manager --set-disabled epel

# Yeni bir depo URL'si ekle
sudo dnf config-manager --add-repo http://ornek.com/yeni/depo.repo
```

Alternatif olarak, ilgili `.repo` dosyasındaki `enabled=1` veya `enabled=0` satırını manuel olarak da düzenleyebilirsiniz.

## Örnek: EPEL Deposunu Ekleme

EPEL (Extra Packages for Enterprise Linux), Fedora topluluğu tarafından yönetilen ve RHEL tabanlı dağıtımlar için birçok ek paket içeren popüler bir depodur.

Modern RHEL, CentOS Stream, Rocky Linux, AlmaLinux sürümlerine EPEL eklemek için genellikle ilgili `epel-release` paketini kurmak yeterlidir:

```bash
# EPEL deposunu kur ve etkinleştir
sudo dnf install epel-release -y

# Depo listesini kontrol et
sudo dnf repolist
```

Bu komut, gerekli `.repo` dosyasını ve GPG anahtarını `/etc/yum.repos.d/` altına otomatik olarak ekler.

## Depo Kaldırma

Bir depo genellikle onu ekleyen paket (örneğin `epel-release`) kaldırılarak sistemden kaldırılır:

```bash
# EPEL deposunu kaldır
sudo dnf remove epel-release
```

Eğer depo manuel olarak bir `.repo` dosyası ile eklenmişse, ilgili `.repo` dosyasını `/etc/yum.repos.d/` dizininden silmek veya `enabled=0` olarak ayarlamak yeterlidir. Depo kaldırıldıktan veya devre dışı bırakıldıktan sonra `dnf clean all` komutu ile önbelleği temizlemek iyi bir pratik olabilir.


# Network Ayarları

Modern RHEL tabanlı dağıtımlarda (RHEL 7+, CentOS 7+, Fedora, CentOS Stream, Rocky Linux, AlmaLinux) ağ yapılandırması varsayılan olarak **NetworkManager** servisi tarafından yönetilir. NetworkManager, ağ bağlantılarını ve cihazlarını yönetmek için dinamik ve esnek bir sistem sunar.

Yapılandırma için çeşitli araçlar mevcuttur:

* **`nmcli`**: Kapsamlı bir komut satırı aracı. Betiklerde (scripting) ve otomasyonda kullanışlıdır.
* **`nmtui`**: Terminal üzerinde çalışan, menü tabanlı, kullanımı kolay bir metin arayüzü (Text User Interface).
* **Grafiksel Arayüzler:** GNOME veya KDE gibi masaüstü ortamlarının kendi ağ ayarları arayüzleri (genellikle arka planda NetworkManager kullanır).

Bu bölümde `nmcli` ve `nmtui` üzerine odaklanacağız.

## NetworkManager ile Temel İşlemler (`nmcli`)

`nmcli`, NetworkManager'ı komut satırından yönetmek için ana araçtır.

**Ağ Cihazlarının Durumunu Görme:**\
Sistemdeki ağ cihazlarını ve durumlarını listeler:

```bash
nmcli device status
# veya kısaca:
nmcli dev status
```

Örnek Çıktı:

```
DEVICE  TYPE      STATE      CONNECTION 
enp0s3  ethernet  connected  Kablolu bağlantı 1 
lo      loopback  unmanaged  --                 
```

**Aktif Bağlantıları Görme:**\
Mevcut aktif ağ bağlantılarını listeler:

```bash
nmcli connection show --active
# veya kısaca:
nmcli con show --active
```

**Tüm Tanımlı Bağlantıları Görme:**\
Aktif olsun veya olmasın, sistemde tanımlı tüm bağlantı profillerini listeler:

```bash
nmcli connection show
# veya kısaca:
nmcli con show
```

**Belirli Bir Bağlantının Detaylarını Görme:**\
Bağlantı adını veya UUID'sini kullanarak detayları gösterir:

```bash
nmcli connection show "Kablolu bağlantı 1" 
# veya UUID ile:
# nmcli con show <uuid>
```

Bu komut, IP adresi, ağ maskesi, ağ geçidi, DNS sunucuları gibi birçok detayı gösterir.

## Ağ Ayarlarını Değiştirme (`nmcli`)

**Önemli:** Ağ ayarlarını değiştirirken dikkatli olun. Uzak bir sunucuya bağlıysanız, yanlış bir ayar bağlantınızın kopmasına neden olabilir. Değişiklikler genellikle `sudo` yetkisi gerektirir.

**Statik IP Adresi Ayarlama:**\
Mevcut bir bağlantıyı DHCP'den statik IP'ye geçirmek için:

```bash
# Bağlantı adını öğrenin (örneğin "Kablolu bağlantı 1")
nmcli con show

# IPv4 metodunu 'manual' yap, IP adresini/maskesini, ağ geçidini ve DNS'i ayarla
sudo nmcli con modify "Kablolu bağlantı 1" ipv4.method manual ipv4.addresses 192.168.1.100/24 ipv4.gateway 192.168.1.1 ipv4.dns "8.8.8.8,8.8.4.4"

# Bağlantıyı yeniden etkinleştirerek ayarları uygula
sudo nmcli con down "Kablolu bağlantı 1" && sudo nmcli con up "Kablolu bağlantı 1" 
```

* `ipv4.addresses`: IP adresi ve CIDR formatında alt ağ maskesi (örn. `/24` = `255.255.255.0`).
* `ipv4.gateway`: Varsayılan ağ geçidi.
* `ipv4.dns`: Virgülle ayrılmış DNS sunucu adresleri.

**DHCP'ye Geri Dönme:**

```bash
sudo nmcli con modify "Kablolu bağlantı 1" ipv4.method auto ipv4.gateway "" ipv4.dns ""
sudo nmcli con down "Kablolu bağlantı 1" && sudo nmcli con up "Kablolu bağlantı 1" 
```

**Yeni Bağlantı Ekleme:**\
Örneğin, `enp0s8` cihazı için statik IP ile yeni bir Ethernet bağlantısı eklemek:

```bash
sudo nmcli con add type ethernet con-name "Statik-Eth1" ifname enp0s8 ipv4.method manual ipv4.addresses 10.0.0.50/24 ipv4.gateway 10.0.0.1 ipv4.dns "10.0.0.1"
```

## Metin Arayüzü (`nmtui`)

Komut satırı seçenekleri karmaşık geliyorsa, `nmtui` daha kolay bir alternatif sunar. Terminalde `nmtui` komutunu çalıştırarak menü tabanlı arayüzü başlatabilirsiniz.

```bash
sudo nmtui
```

`nmtui` içinde ok tuşları ve Enter ile gezinebilirsiniz:

* **Edit a connection:** Mevcut bağlantıları düzenlemek veya yeni bağlantı eklemek için kullanılır. Statik IP, DHCP, DNS gibi ayarları kolayca yapabilirsiniz.
* **Activate a connection:** Bağlantıları etkinleştirmek veya devre dışı bırakmak için kullanılır.
* **Set system hostname:** Sistem ana bilgisayar adını değiştirmek için kullanılır.

Değişiklik yaptıktan sonra "OK" veya "Back" seçenekleriyle menülerden çıkın ve en son ana menüden "Quit" seçeneğini seçin. `nmtui` ile yapılan değişiklikler de NetworkManager tarafından yönetilir ve kalıcı olur.

## Eski Yöntem (`ifcfg` Dosyaları)

RHEL/CentOS 6 ve öncesinde ağ yapılandırması `/etc/sysconfig/network-scripts/` dizini altındaki `ifcfg-<arayüz_adı>` (örn. `ifcfg-eth0`, `ifcfg-enp0s3`) dosyaları düzenlenerek ve `network` servisi (`service network restart` veya `systemctl restart network`) yeniden başlatılarak yapılırdı.

Örnek bir statik IP için `ifcfg-enp0s3` dosyası:

```
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=enp0s3
UUID=...
DEVICE=enp0s3
ONBOOT=yes
IPADDR=192.168.1.100
PREFIX=24  # veya NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=8.8.8.8
DNS2=8.8.4.4
```

Modern sistemlerde NetworkManager genellikle bu dosyaları okuyabilir ancak yeni yapılandırmalar için `nmcli` veya `nmtui` kullanmak daha standart ve önerilen yöntemdir. Eğer NetworkManager kurulu ve aktifse, `ifcfg` dosyalarını doğrudan düzenlemek yerine NetworkManager araçlarını kullanmak çakışmaları önler. Bazı minimal kurulumlarda veya özel durumlarda NetworkManager yerine hala `network` servisi kullanılabilir, ancak bu durum giderek azalmaktadır.


# Debian

Debian, tamamen gönüllüler tarafından geliştirilen, özgür yazılım ilkelerine sıkı sıkıya bağlı, köklü ve yaygın olarak kullanılan bir Linux dağıtımıdır. Kararlılığı, güvenliği ve devasa paket deposu ile bilinir. Popüler Ubuntu dağıtımı da Debian'ı temel alır.

## Genel Özellikler

* **Köken:** Bağımsız bir topluluk projesidir. "Debian Sosyal Sözleşmesi" ve "Debian Özgür Yazılım Yönergeleri" projenin temelini oluşturur.
* **Sürümler:** Debian'ın genellikle üç ana sürüm dalı bulunur:
  * `stable` (Kararlı): Uzun süre test edilmiş, kararlı ve güvenilir sürümdür. Sunucular için genellikle bu sürüm tercih edilir, ancak paketleri biraz daha eski olabilir.
  * `testing` (Test): Bir sonraki kararlı sürüm için hazırlanan paketleri içerir. `stable`'a göre daha günceldir ancak daha az test edilmiştir.
  * `unstable` (Sid): En güncel paketlerin bulunduğu geliştirme dalıdır. Kararlılık garantisi yoktur.
* **Paket Yönetimi:** `.deb` paket formatını ve `apt` (Advanced Package Tool) paket yöneticisi ailesini (örn. `apt`, `apt-get`, `apt-cache`) kullanır. `dpkg` ise `.deb` dosyalarıyla doğrudan çalışmak için kullanılan düşük seviyeli araçtır.
  * [deb Paketleri](/temel-dagitimlar/debian/deb-paketleri)
  * [apt Paket Yöneticisi (aptitude yerine)](https://github.com/VeriTeknik/linux_kitap/blob/master/temel-dagitimlar/debian/aptitude-paket-yoeneticisi.md) (Dosya adı eski kalmış, içerik güncellenmeli)
* **Depo Yönetimi:** Yazılım depoları `/etc/apt/sources.list` dosyasında ve `/etc/apt/sources.list.d/` dizini altındaki `.list` dosyalarında tanımlanır.
  * [Repo Ayarları](/temel-dagitimlar/debian/repo-ayarlari)
* **Ağ Yönetimi:** Geleneksel olarak `/etc/network/interfaces` dosyası ve `ifup`/`ifdown` komutları ile yönetilirdi. Modern Debian sürümleri (özellikle masaüstü kurulumları) NetworkManager'ı da destekler ve kullanabilir. Sunucu kurulumlarında hala `/etc/network/interfaces` yaygın olarak kullanılır, ancak `systemd-networkd` de bir alternatiftir.
  * [Network Ayarları](/temel-dagitimlar/debian/network-ayarlari)
* **Felsefe:** Özgür yazılım, topluluk, kararlılık ve evrensel bir işletim sistemi olma hedefleri ön plandadır.
* **Hedef Kitle:** Sunucular, masaüstü kullanıcıları, geliştiriciler, özgür yazılım meraklıları, kararlılık ve geniş paket seçeneği arayanlar.

**Kurulum:**\
Debian kurulumu, metin tabanlı veya grafiksel bir yükleyici ile yapılır. Kurulum sırasında dil, klavye, ağ, disk bölümlendirme, yazılım seçimi gibi adımlar bulunur. Detaylı kurulum kılavuzları için resmi Debian belgelerine başvurulmalıdır:

* Debian Kurulum Kılavuzu: <https://www.debian.org/releases/stable/installmanual>

Bu bölümdeki diğer dosyalar, Debian sistemlerde paket yönetimi, depo ayarları ve ağ yapılandırması gibi temel konuları ele alacaktır (içeriklerinin güncellenmesi gerekmektedir).


# deb Paketleri

Debian ve türevi sistemlerde (Ubuntu, Mint vb.) kullanılan temel paket formatı `.deb` uzantılı dosyalardır. Bu dosyalar, programları, kütüphaneleri, yapılandırma dosyalarını ve ilgili betikleri içerir.

**dpkg** (Debian Package), `.deb` dosyalarını kurmak, kaldırmak ve sorgulamak için kullanılan düşük seviyeli komut satırı aracıdır.

**Önemli Not:** `dpkg`, paketleri doğrudan yönetir ancak **bağımlılıkları otomatik olarak çözmez veya yönetmez**. Paket kurma, kaldırma veya güncelleme gibi işlemler için genellikle `apt` (veya `apt-get`) gibi daha üst seviye paket yöneticilerinin kullanılması **şiddetle tavsiye edilir**. `apt`, depoları kullanarak gerekli bağımlılıkları otomatik olarak indirir ve kurar. `dpkg` daha çok indirilen `.deb` dosyalarını manuel olarak kurmak (ancak bağımlılıkları sağlamak sizin sorumluluğunuzdadır), kurulu paketleri sorgulamak veya düşük seviyeli paket manipülasyonları için kullanılır.

## `dpkg` Komutu ile Sorgulama ve Yönetim

**Paket Kurulumu (Bağımlılıkları Çözmez!):**

İndirilmiş bir `.deb` dosyasını kurmak için `-i` (veya `--install`) kullanılır:

```bash
sudo dpkg -i paket-dosyası.deb
```

**Not:** Eğer bu paket, sistemde kurulu olmayan başka paketlere bağımlıysa, `dpkg` hata verecek ve paketi yapılandırmayacaktır. Bu durumda genellikle `sudo apt --fix-broken install` komutu ile eksik bağımlılıkların kurulması gerekir. Yerel bir `.deb` dosyasını bağımlılıklarıyla birlikte kurmanın daha kolay yolu `apt` kullanmaktır: `sudo apt install ./paket-dosyası.deb`.

**Yüklü Paketleri Listeleme ve Sorgulama:**

Sistemde kurulu paketleri (ve durumlarını) listelemek için `-l` (veya `--list`) kullanılır (`less` ile kullanmak faydalıdır):

```bash
# dpkg -l
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                                        Version                                             Architecture Description
+++-===========================================-===================================================-============-=====================================================================================================================
ii  accountsservice                             0.6.35-0ubuntu7.2                                   amd64        query and manipulate user account information
ii  acl                                         2.2.52-1                                            amd64        Access control list utilities
ii  acpi-support                                0.142                                               amd64        scripts for handling many ACPI events
ii  acpid                                       1:2.0.21-1ubuntu2                                   amd64        Advanced Configuration and Power Interface event daemon
ii  add-apt-key                                 1.0-0.5                                             all          Command line tool to add GPG keys to the APT keyring
ii  adduser                                     3.113+nmu3ubuntu3                                   all          add and remove users and groups
ii  adobe-flashplugin                           1:20151110.1-0trusty1                               amd64        Adobe Flash Player plugin
ii  alsa-base                                   1.0.25+dfsg-0ubuntu4                                all          ALSA driver configuration files
ii  alsa-utils                                  1.0.27.2-1ubuntu2                                   amd64        Utilities for configuring and using ALSA
ii  anacron                                     2.3-20ubuntu1                                       amd64        cron-like program that doesn't go by time
ii  apg                                         2.2.3.dfsg.1-2ubuntu1                               amd64        Automated Password Generator - Standalone version
ii  apt                                         1.0.1ubuntu2.10                                     amd64        commandline package manager
ii  apt-clone                                   0.3.1~ubuntu11.1                                    all          Script to create state bundles
ii  apt-transport-https                         1.0.1ubuntu2.10                                     amd64        https download transport for APT
ii  apt-utils                                   1.0.1ubuntu2.10                                     amd64        package management related utility programs
```

Belirli bir paketin yüklü olup olmadığını görmek için, paket ismi verebilirsiniz.

```bash
# Belirli bir paketin durumunu listele (grep ile filtreleyerek)
dpkg -l | grep htop
# veya doğrudan paket adıyla:
dpkg -l htop 
```

Çıktıdaki ilk iki harf (örn. `ii`) paketin durumunu gösterir:

* İlk harf (İstenen Durum): `i` (Install), `h` (Hold), `r` (Remove), `p` (Purge).
* İkinci harf (Mevcut Durum): `n` (Not installed), `i` (Installed), `c` (Config-files), `U` (Unpacked), `F` (Half-configured), `H` (Half-installed), `W` (Triggers-awaited), `T` (Triggers-pending).
* `ii`: İstenen ve mevcut durum "Installed".
* `rc`: Paket kaldırılmış (Removed) ancak yapılandırma dosyaları duruyor (Config-files).

Kurulu bir paket hakkında detaylı bilgi almak için `-s` (veya `--status`) kullanılır:

```bash
# dpkg -s htop
Package: htop
Status: install ok installed
Priority: optional
Section: utils
Installed-Size: 184
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Architecture: amd64
Version: 1.0.2-3
Depends: libc6 (>= 2.15), libncursesw5 (>= 5.6+20070908), libtinfo5
Suggests: strace, ltrace
Description: interactive processes viewer
 Htop is an ncursed-based process viewer similar to top, but it
 allows one to scroll the list vertically and horizontally to see
 all processes and their full command lines.
 .
 Tasks related to processes (killing, renicing) can be done without
 entering their PIDs.
Original-Maintainer: Eugene V. Lyubimkin <jackyf@debian.org>
Homepage: http://htop.sourceforge.net
```

```bash
# dpkg -s atop
dpkg-query: package 'atop' is not installed and no information is available
Use dpkg --info (= dpkg-deb --info) to examine archive files,
and dpkg --contents (= dpkg-deb --contents) to list their contents.
```

Kurulu bir paketin sisteme hangi dosyaları yüklediğini listelemek için `-L` (veya `--listfiles`) kullanılır:

```bash
dpkg -L htop
```

Belirli bir dosyanın hangi kurulu pakete ait olduğunu bulmak için `-S` (veya `--search`) kullanılır:

```bash
dpkg -S /bin/htop
```

**Paket Kaldırma:**

**Uyarı:** Aşağıdaki komutlar bağımlılıkları otomatik yönetmez. Genellikle `apt remove` veya `apt purge` kullanın.

Yüklü bir paketi kaldırmak (yapılandırma dosyaları kalır) için `-r` (veya `--remove`) kullanılır:

```bash
sudo dpkg -r htop
```

Bir paketi yapılandırma dosyalarıyla birlikte tamamen kaldırmak için `-P` (veya `--purge`) kullanılır:

```bash
sudo dpkg -P htop
```

**Diğer İşlemler:**

Bir `.deb` paket dosyasının içeriğini (kurmadan) listelemek için `-c` (veya `--contents`) kullanılır:

```bash
dpkg -c paket-dosyası.deb
```

Bir `.deb` paket dosyası hakkında bilgi (kontrol dosyası içeriği) almak için `-I` (veya `--info`) kullanılır:

```bash
dpkg -I paket-dosyası.deb
```

Kurulumu tamamlanmamış veya yarıda kalmış paketleri yapılandırmak için `--configure -a` kullanılır:

```bash
sudo dpkg --configure -a
```

(Bu işlem genellikle `apt --fix-broken install` komutunun bir parçası olarak da çalıştırılır.)

Özetle, `dpkg` `.deb` paketleriyle düşük seviyede çalışmak için temel araçtır, ancak bağımlılık yönetimi karmaşıklığı nedeniyle günlük kullanımda `apt` komutları tercih edilmelidir.


# apt Paket Yöneticisi

Debian ve türevi sistemlerde (Ubuntu, Mint vb.) paket yönetimi için kullanılan ana araç **APT** (Advanced Package Tool) ailesidir. Bu aile, paketleri kurmak, güncellemek, kaldırmak ve depoları yönetmek için çeşitli komut satırı araçları sunar.

## `apt`, `apt-get`, `apt-cache` ve `aptitude`

* **`apt`**: Modern ve kullanıcı dostu komut satırı arayüzüdür. `apt-get` ve `apt-cache`'in en sık kullanılan komutlarını daha basit bir sözdizimi ve ek özelliklerle (örn. ilerleme çubuğu) birleştirir. **Genellikle günlük kullanım için önerilen araçtır.**
* **`apt-get`**: Paketleri kurmak, güncellemek ve kaldırmak için kullanılan daha eski, temel komut satırı aracıdır. Betiklerde (scripting) hala yaygın olarak kullanılır.
* **`apt-cache`**: Paket deposu önbelleğini sorgulamak (paket aramak, bilgi göstermek vb.) için kullanılan eski araçtır. `apt` komutu bu işlevleri de içerir.
* **`aptitude`**: Hem komut satırı hem de metin tabanlı interaktif bir arayüz sunan alternatif bir paket yöneticisidir. Özellikle karmaşık bağımlılık sorunlarını çözmede bazen `apt` veya `apt-get`'ten daha yetenekli olabilir.

Bu bölümde, modern ve önerilen `apt` komutuna odaklanacağız. Komutların çoğu `sudo` yetkisi gerektirir.

## Paket Listelerini Güncelleme (`update`)

Paket kurulumu veya güncellemesi yapmadan önce, sistemin mevcut depolarındaki paket listelerini yenilemek önemlidir. Bu işlem, hangi paketlerin yeni sürümlerinin olduğunu sisteme bildirir.

```bash
sudo apt update
```

Bu komut herhangi bir paketi kurmaz veya güncellemez, sadece paket bilgilerini günceller.

## Paketleri Güncelleme (`upgrade`, `full-upgrade`)

Kurulu paketleri mevcut depolardaki en son sürümlerine yükseltmek için `upgrade` kullanılır:

```bash
# Kurulu paketleri güncelle (yenilerini kurmaz, mevcutları kaldırmaz)
sudo apt upgrade
```

Onay istenecektir. `-y` parametresi ile onay otomatik olarak verilebilir:

```bash
sudo apt upgrade -y
```

`upgrade` komutu, mevcut paketleri güncellerken sistemde kurulu paketleri kaldırmaz veya yenilerini eklemez. Eğer bir güncelleme işlemi yeni bağımlılıkların kurulmasını veya çakışan paketlerin kaldırılmasını gerektiriyorsa, `upgrade` o paketi güncellemez.

Bu tür durumları da yöneterek (gerekirse paket kaldırıp/ekleyerek) sistemi tamamen güncellemek için `full-upgrade` (eski `apt-get dist-upgrade` komutunun eşdeğeri) kullanılır:

```bash
sudo apt full-upgrade -y
```

Genellikle sunucularda `upgrade` daha kontrollü bir seçenekken, masaüstü sistemlerde veya sürüm yükseltmelerinde `full-upgrade` gerekebilir.

Hangi paketlerin güncellenebileceğini görmek için:

```bash
apt list --upgradable
```

## Paket Arama (`search`)

Depolarda belirli bir anahtar kelimeye göre paket aramak için `search` kullanılır:

```bash
# Adında veya açıklamasında 'htop' geçen paketleri ara
apt search htop
```

## Paket Bilgisi Gösterme (`show`)

Belirli bir paket hakkında detaylı bilgi (sürüm, bağımlılıklar, açıklama, boyut vb.) almak için `show` kullanılır:

```bash
apt show htop
```

## Paket Kurma (`install`)

Bir veya daha fazla paketi kurmak için `install` kullanılır. `apt`, gerekli bağımlılıkları otomatik olarak bulup kurar:

```bash
sudo apt install htop screen vim
```

Yerel bir `.deb` dosyasını kurarken de `apt` kullanmak, bağımlılıkların depolardan otomatik olarak çözülmesini sağlar:

```bash
sudo apt install ./indirilen-paket.deb
```

## Paket Kaldırma (`remove`, `purge`)

Bir paketi kaldırmak (ancak yapılandırma dosyalarını sistemde bırakmak) için `remove` kullanılır:

```bash
sudo apt remove htop
```

Bir paketi yapılandırma dosyalarıyla birlikte tamamen kaldırmak için `purge` kullanılır:

```bash
sudo apt purge htop
```

## Gereksiz Paketleri Kaldırma (`autoremove`)

Bir paket kurulduğunda otomatik olarak kurulan ancak artık başka hiçbir kurulu paketin ihtiyaç duymadığı bağımlılıkları sistemden kaldırmak için `autoremove` kullanılır. Genellikle `remove` veya `purge` işleminden sonra çalıştırılması önerilir:

```bash
sudo apt autoremove
```

## Kurulu Paketleri Listeleme (`list`)

Sistemde kurulu paketleri listelemek için:

```bash
apt list --installed | less
```

Belirli bir paketin kurulu olup olmadığını kontrol etmek için:

```bash
apt list --installed | grep htop
# veya daha basitçe:
apt list htop 
```

## Diğer Kullanışlı `apt` Komutları

* **`edit-sources`**: `/etc/apt/sources.list` dosyasını düzenlemek için varsayılan metin düzenleyiciyi açar.
* **`clean`**: İndirilen `.deb` paket dosyalarının yerel önbelleğini (`/var/cache/apt/archives/`) temizler. Disk alanı açmak için kullanılabilir.

  ```bash
  sudo apt clean
  ```
* **`autoclean`**: `clean` gibidir ancak sadece artık depolarda bulunmayan veya daha yeni sürümü olan eski paket dosyalarını temizler.

## Easter Egg

`apt` komutunun da (tıpkı `apt-get` gibi) küçük bir sürprizi vardır:

```bash
apt moo
```

`apt`, Debian tabanlı sistemlerde paket yönetimini kolaylaştıran güçlü ve modern bir araçtır. Çoğu durumda `apt-get` ve `apt-cache` yerine tercih edilebilir.


# Repo Ayarları

`apt` paket yöneticisi, paketleri indirmek için **depo** (repository) adı verilen sunuculardaki kaynak listelerini kullanır. Bu depoların tanımları `/etc/apt/sources.list` dosyasında ve `/etc/apt/sources.list.d/` dizini altındaki `.list` uzantılı dosyalarda bulunur.

## `sources.list` Dosyasının Yapısı

`/etc/apt/sources.list` dosyasındaki her satır genellikle şu formatı takip eder:

```
deb http://deb.debian.org/debian/ bookworm main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian/ bookworm main contrib non-free non-free-firmware

deb http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb-src http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware

# bookworm-updates, previously known as 'volatile'
deb http://deb.debian.org/debian/ bookworm-updates main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian/ bookworm-updates main contrib non-free non-free-firmware
```

(Yukarıdaki örnek Debian 12 "Bookworm" içindir.)

* **Tür:**
  * `deb`: İkili (binary) paketler için depo (en yaygın).
  * `deb-src`: Kaynak kod paketleri için depo (genellikle geliştiriciler için gereklidir).
* **URI:** Deponun adresi (örn. `http://deb.debian.org/debian/`). Genellikle ülkeye özgü bir ayna (mirror) adresi de kullanılabilir (örn. `http://ftp.tr.debian.org/debian/`).
* **Dağıtım (Distribution):** Hangi Debian sürümünün kullanılacağını belirtir. Bu, sürümün kod adı (`bookworm`, `trixie` vb.) veya sürüm dalı (`stable`, `testing`, `unstable`) olabilir. Güvenlik güncellemeleri için genellikle `<kodadı>-security` (örn. `bookworm-security`), önemli güncellemeler için `<kodadı>-updates` (örn. `bookworm-updates`) kullanılır.
* **Bileşen(ler) (Component(s)):** Deponun hangi bölümlerinin kullanılacağını belirtir. Boşlukla ayrılırlar. Standart Debian bileşenleri şunlardır:
  * `main`: Debian Özgür Yazılım Yönergeleri'ne (DFSG) uyan, tamamen özgür paketleri içerir. Debian sisteminin temelini oluşturur.
  * `contrib`: DFSG'ye uyan ancak `non-free` bölümündeki paketlere bağımlı olan özgür paketleri içerir.
  * `non-free`: DFSG'ye uymayan, yani özgür olmayan lisanslara sahip paketleri içerir (örn. bazı aygıt sürücüleri, firmware'ler, özel yazılımlar).
  * `non-free-firmware`: Debian 12 ile birlikte `non-free` bölümünden ayrılan, özgür olmayan firmware dosyalarını içeren bileşen. Kurulum sırasında veya sonrasında bazı donanımların çalışması için gerekebilir.

## `/etc/apt/sources.list.d/` Dizini

Sistemin ana `sources.list` dosyasını temiz tutmak ve üçüncü parti depoları (örneğin Google Chrome, Spotify, Docker vb. tarafından sağlananlar) veya kişisel depoları yönetmek için `/etc/apt/sources.list.d/` dizini kullanılır. Bu dizine eklenen `.list` uzantılı her dosya, `sources.list` ile aynı formatta depo tanımları içerebilir. `apt update` komutu bu dizindeki dosyaları da okur.

Örnek bir `/etc/apt/sources.list.d/google-chrome.list` dosyası:

```
deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main
```

## Depo Eklemek ve Yönetmek

**Manuel Düzenleme:**\
Depoları yönetmenin en temel yolu `/etc/apt/sources.list` dosyasını veya `/etc/apt/sources.list.d/` altındaki dosyaları bir metin düzenleyici ile (root yetkisiyle) düzenlemektir.

**`add-apt-repository` (Özellikle Ubuntu/PPA için):**\
Bu komut, özellikle Ubuntu'daki PPA (Personal Package Archives) depolarını eklemek için kullanılır. Depo adresini, dağıtım bilgilerini ve gerekli GPG anahtarını otomatik olarak eklemeye çalışır. Debian'da da bulunabilir (`software-properties-common` paketi ile gelir) ancak PPA'lar Debian için resmi olarak desteklenmez ve kararlılık sorunlarına yol açabilir.

```bash
# Örnek bir PPA ekleme (Ubuntu'da yaygın)
# sudo add-apt-repository ppa:webupd8team/java
# sudo apt update 
```

Normal depoları eklemek için de kullanılabilir, ancak genellikle manuel düzenleme veya ilgili yazılımın belgelerinde belirtilen yöntem (örn. GPG anahtarını indirip `.list` dosyası oluşturma) daha yaygındır.

**GPG Anahtarları:**\
Güvenli depolar, paketlerin orijinalliğini doğrulamak için GPG anahtarları kullanır. Bir depo eklediğinizde, genellikle o deponun GPG anahtarını da sisteme eklemeniz gerekir. Bu işlem genellikle `wget` veya `curl` ile anahtarı indirip `gpg --dearmor` ile dönüştürdükten sonra `/etc/apt/trusted.gpg.d/` dizinine kaydetmek veya `apt-key add` (eski yöntem, daha az güvenli) komutu ile yapılır. Modern `.list` dosyaları `signed-by` seçeneği ile doğrudan anahtar dosyasını belirtebilir. Üçüncü parti depoları eklerken, ilgili yazılımın belgelerindeki adımları takip etmek en doğrusudur.

## Değişiklikleri Uygulama (`apt update`)

`/etc/apt/sources.list` dosyasında veya `/etc/apt/sources.list.d/` altındaki dosyalarda herhangi bir değişiklik yaptıktan sonra, `apt`'nin yeni depo bilgilerini ve paket listelerini alması için **mutlaka** aşağıdaki komut çalıştırılmalıdır:

```bash
sudo apt update
```

Bu komut, yeni eklenen depolardaki paketleri `apt search` ile aranabilir ve `apt install` ile kurulabilir hale getirir.


# Network Ayarları

Debian tabanlı sistemlerde ağ yapılandırması için tarihsel olarak `/etc/network/interfaces` dosyası ve `ifup`/`ifdown` komutları (ve bunları yöneten `networking` servisi) kullanılmıştır. Ancak modern Debian sürümleri, özellikle masaüstü kurulumları, **NetworkManager**'ı da yaygın olarak kullanır. Sunucu ortamlarında ise `/etc/network/interfaces` hala sıkça tercih edilmekle birlikte, **systemd-networkd** de giderek popülerleşen bir alternatiftir.

**Önemli:** Bir ağ arayüzü (örn. `eth0`) aynı anda sadece *bir* yönetim sistemi tarafından kontrol edilmelidir (ya `/etc/network/interfaces`, ya NetworkManager, ya da systemd-networkd). Farklı sistemlerle aynı arayüzü yapılandırmaya çalışmak çakışmalara ve beklenmedik davranışlara yol açabilir.

## Geleneksel Yöntem: `/etc/network/interfaces`

Bu yöntemde, tüm ağ arayüzlerinin yapılandırması `/etc/network/interfaces` dosyasında tanımlanır. Değişikliklerin uygulanması için genellikle ilgili arayüz `ifdown <arayüz>` ve `ifup <arayüz>` komutlarıyla yeniden başlatılır veya `networking` servisi (`sudo systemctl restart networking` veya eski sistemlerde `sudo service networking restart`) yeniden başlatılır.

**Örnek `/etc/network/interfaces` Dosyası:**

```
# Loopback arayüzü
auto lo
iface lo inet loopback

# eth0 arayüzü - Statik IP
auto eth0
iface eth0 inet static
    address 94.103.47.78
    netmask 255.255.255.128 # veya address 94.103.47.78/25
    gateway 94.103.47.1
    # İsteğe bağlı: DNS sunucuları (resolvconf paketi kuruluysa)
    # dns-nameservers 8.8.8.8 8.8.4.4
    # dns-search example.com

# eth1 arayüzü - DHCP
auto eth1
iface eth1 inet dhcp
```

* `auto <arayüz>`: Sistem başlangıcında arayüzün otomatik olarak etkinleştirilmesini sağlar.
* `iface <arayüz> inet <metod>`: Arayüz için IPv4 yapılandırmasını tanımlar.
  * `loopback`: Geri döngü arayüzü (127.0.0.1).
  * `static`: Statik IP adresi yapılandırması. `address`, `netmask` (veya CIDR prefix), `gateway` gibi parametreler kullanılır.
  * `dhcp`: IP adresini DHCP sunucusundan otomatik olarak alır.
* `address`: IP adresi.
* `netmask`: Alt ağ maskesi. Alternatif olarak `address` satırında CIDR notasyonu (örn. `192.168.1.100/24`) kullanılabilir.
* `gateway`: Varsayılan ağ geçidi.
* `dns-nameservers`: Kullanılacak DNS sunucuları (boşlukla ayrılmış). Bu satırın çalışması için genellikle `resolvconf` paketinin kurulu olması gerekir. DNS sunucuları ayrıca `/etc/resolv.conf` dosyasında da tanımlanabilir.

## Modern Yöntem 1: NetworkManager

Özellikle masaüstü ve dizüstü bilgisayarlarda veya sık sık ağ değiştiren sistemlerde NetworkManager varsayılan olabilir. NetworkManager, ağları dinamik olarak yönetir ve `nmcli` (komut satırı) veya `nmtui` (metin arayüzü) gibi araçlarla yapılandırılır.

NetworkManager'ın kurulu ve aktif olup olmadığını kontrol etmek için:

```bash
sudo systemctl status NetworkManager
```

Eğer NetworkManager aktifse, `/etc/network/interfaces` dosyasındaki arayüz tanımları genellikle NetworkManager tarafından *yönetilmez* olarak işaretlenir veya dosya içeriği daha basit tutulur. NetworkManager yapılandırması için RHEL/CentOS bölümündeki [Network Ayarları (NetworkManager)](/temel-dagitimlar/centos/network-ayarlari) kısmına bakabilirsiniz. `nmcli` ve `nmtui` komutları Debian üzerinde de benzer şekilde çalışır.

## Modern Yöntem 2: systemd-networkd

`systemd-networkd`, özellikle sunucular ve gömülü sistemler için tasarlanmış, systemd ile entegre çalışan modern bir ağ yapılandırma servisidir. Yapılandırma `/etc/systemd/network/` dizini altındaki `.network` uzantılı dosyalarla yapılır.

Örnek bir statik IP için `/etc/systemd/network/10-static-eth0.network` dosyası:

```ini
[Match]
Name=eth0

[Network]
Address=192.168.1.100/24
Gateway=192.168.1.1
DNS=8.8.8.8
DNS=8.8.4.4
```

Yapılandırma sonrası servis etkinleştirilir ve başlatılır:

```bash
sudo systemctl enable systemd-networkd
sudo systemctl start systemd-networkd
# DNS için systemd-resolved servisi de gerekebilir
# sudo systemctl enable systemd-resolved
# sudo systemctl start systemd-resolved 
```

Hangi yöntemin kullanılacağı sistemin kurulumuna ve yöneticinin tercihine bağlıdır. Sunucu kurulumlarında `/etc/network/interfaces` hala yaygın olsa da, NetworkManager ve systemd-networkd daha modern ve esnek alternatifler sunmaktadır.


# FreeBSD

FreeBSD, Berkeley Software Distribution (BSD) temelinden gelen, açık kaynaklı, Unix benzeri bir işletim sistemidir. Linux'tan farklı bir çekirdeğe ve temel kullanıcı alanı araçlarına (userland) sahiptir. Genellikle kararlılığı, yüksek performansı (özellikle ağ konusunda) ve gelişmiş özellikleriyle bilinir.

## Genel Özellikler

* **Köken:** Kaliforniya Üniversitesi, Berkeley'de geliştirilen BSD Unix'ten türemiştir.
* **Çekirdek ve Userland:** Linux dağıtımlarının aksine, FreeBSD çekirdeği ve temel kullanıcı alanı araçları (C kütüphanesi, kabuk, temel komutlar vb.) tek bir proje kapsamında birlikte geliştirilir. Bu, daha entegre ve tutarlı bir sistem sağlar.
* **Lisans:** Linux'un kullandığı GPL yerine daha esnek olan BSD lisansını kullanır.
* **Paket Yönetimi:** İki ana sistem kullanılır:
  * **Ports Collection:** `/usr/ports` altında bulunan, yazılımları kaynak koddan derleyip kurmayı sağlayan bir sistemdir. Yüksek düzeyde özelleştirme imkanı sunar.
  * **pkg:** Önceden derlenmiş ikili (binary) paketleri yönetmek için kullanılan modern paket yöneticisidir. Hızlı kurulum sağlar.
  * [Ports ve pkg Yönetimi](https://github.com/VeriTeknik/linux_kitap/blob/master/temel-dagitimlar/freebsd/port-ve-pck_add-yoenetimi.md) (Dosya adı eski `pkg_add`'ı içeriyor, içerik güncellenmeli)
* **Sistem Güncelleme:** Temel sistem ve kurulan paketler ayrı ayrı güncellenir. Temel sistem genellikle `freebsd-update` aracıyla, paketler ise `pkg upgrade` ile güncellenir.
  * [Güncelleme Teknikleri](/temel-dagitimlar/freebsd/guencelleme-teknikleri)
* **Ağ Yönetimi:** Ağ yapılandırması genellikle `/etc/rc.conf` dosyası üzerinden yapılır. `ifconfig` komutu arayüzleri yapılandırmak için kullanılır.
  * [Network Ayarları](/temel-dagitimlar/freebsd/network-ayarlari)
* **Öne Çıkan Özellikler:** Güçlü ve kararlı ağ yığını (network stack), ZFS dosya sisteminin gelişmiş entegrasyonu, Jails (hafif işletim sistemi seviyesinde sanallaştırma/konteyner mekanizması), DTrace (dinamik izleme aracı) gibi özellikleriyle tanınır.
* **Hedef Kitle:** Sunucular (özellikle ağ servisleri), yüksek performans ve kararlılık gerektiren sistemler, gömülü sistemler, Unix felsefesine ve BSD lisansına yakınlık duyanlar.

**Kurulum:**\
FreeBSD kurulumu genellikle `bsdinstall` metin tabanlı yükleyici ile yapılır. Kurulum sırasında klavye düzeni, ana bilgisayar adı, kurulacak bileşenler (Ports, src vb.), disk bölümlendirme (UFS veya ZFS), ağ ayarları, saat dilimi, root şifresi ve kullanıcı oluşturma gibi adımlar bulunur. Detaylı kurulum kılavuzları için resmi FreeBSD El Kitabı'na başvurulmalıdır:

* FreeBSD El Kitabı - Kurulum: <https://docs.freebsd.org/en/books/handbook/bsdinstall/>

Bu bölümdeki diğer dosyalar, FreeBSD sistemlerde paket yönetimi, sistem güncelleme ve ağ yapılandırması gibi temel konuları ele alacaktır (içeriklerinin güncellenmesi gerekmektedir).


# Ports ve pkg Yönetimi

FreeBSD, üçüncü parti yazılımları kurmak ve yönetmek için iki ana sistem sunar: **Ports Koleksiyonu** ve **pkg** ikili (binary) paket yöneticisi. Her iki sistem de aynı yazılım havuzuna erişir ancak farklı yöntemlerle çalışır.

## 1. Ports Koleksiyonu (`/usr/ports`)

Ports Koleksiyonu, binlerce üçüncü parti yazılımı FreeBSD üzerinde kaynak koddan derlemek için gerekli dosyaları (Makefile, yamalar, açıklamalar vb.) içeren bir dizin ağacıdır (genellikle `/usr/ports`). Bu yöntem, derleme seçeneklerini özelleştirerek yazılımı optimize etme imkanı sunar ancak paket kurma işlemi daha uzun sürer ve derleme için gerekli araçların (derleyici, kütüphaneler vb.) sistemde bulunmasını gerektirir.

**Ports Ağacını Alma ve Güncelleme:**

* **`portsnap` (Önerilen):** Ports ağacının sıkıştırılmış anlık görüntülerini (snapshot) kullanarak hızlı bir şekilde ilk alımı ve güncellemeyi sağlar.

  ```bash
  # İlk kez alırken:
  sudo portsnap fetch extract

  # Sonraki güncellemeler için:
  sudo portsnap fetch update
  ```
* **`git` (Alternatif):** Ports ağacını bir Git deposu olarak klonlamak ve güncellemek de mümkündür.

**Port Bulma:**

* **`whereis`:** Belirli bir komutun port dizinini bulmak için kullanılabilir.

  ```bash
  whereis htop 
  # Örnek Çıktı: htop: /usr/ports/sysutils/htop
  ```
* **`make search`:** Ports ağacı içinde anahtar kelimeye göre arama yapar (indeks oluşturulmuşsa hızlıdır).

  ```bash
  cd /usr/ports
  sudo make search name=htop 
  # veya daha geniş arama:
  # sudo make search key=process
  ```

**Port Kurulumu:**

1. **Dizine Git:** İlgili portun dizinine gidin.

   ```bash
   cd /usr/ports/sysutils/htop
   ```
2. **(İsteğe Bağlı) Seçenekleri Yapılandırma:** Birçok port, derleme sırasında etkinleştirilecek veya devre dışı bırakılacak özellikleri seçmenize olanak tanır.

   ```bash
   sudo make config # Metin tabanlı menü açılır
   # Veya tüm bağımlılıklar için seçenekleri sorması:
   # sudo make config-recursive
   ```

   Seçenekler genellikle `/var/db/ports/` altında saklanır.
3. **Derleme, Kurulum ve Temizlik:**

   ```bash
   # Derle, kur ve derleme sonrası geçici dosyaları temizle
   sudo make install clean 
   ```

   Bu işlem, gerekli bağımlılıkları da (ya portlardan derleyerek ya da `pkg` ile binary olarak kurarak) otomatik olarak halletmeye çalışır.

**Port Kaldırma:**

İlgili port dizinindeyken:

```bash
sudo make deinstall
```

**Derleme Dosyalarını Temizleme:**

Derleme sırasında oluşan geçici dosyaları (`work` dizini) temizlemek için:

```bash
sudo make clean
```

**Yardımcı Araçlar:**\
Ports koleksiyonunu yönetmek için `portmaster` veya `poudriere` (toplu derleme için) gibi üçüncü parti araçlar da mevcuttur, ancak temel işlemler `make` komutları ile yapılabilir.

## 2. pkg İkili Paket Yöneticisi

`pkg`, FreeBSD için modern ikili (binary) paket yöneticisidir. Önceden derlenmiş paketleri resmi veya üçüncü parti depolardan hızlı bir şekilde kurmayı, güncellemeyi ve kaldırmayı sağlar. Genellikle Ports'a göre çok daha hızlıdır ve derleme gerektirmez. Eski `pkg_add`, `pkg_info` gibi komutların yerini almıştır.

**`pkg`'yi Başlatma (Bootstrapping):**

Eğer sistemde `pkg` kurulu değilse (genellikle ilk kurulumdan sonra gerekir), ilk `pkg` komutu çalıştırıldığında otomatik olarak kurulması teklif edilir:

```bash
# Örneğin:
sudo pkg update 
# Çıktı benzeri:
# The package management tool is not yet installed on your system.
# Do you want to fetch and install it now? [y/N]: y 
# ... pkg kurulur ...
```

Veya manuel olarak:

```bash
sudo pkg bootstrap
```

**Paket Kataloğunu Güncelleme:**

Depolardaki mevcut paket listesini güncellemek için:

```bash
sudo pkg update
```

**Paket Arama:**

Depolarda paket aramak için:

```bash
pkg search htop
pkg search -i screen # Büyük/küçük harf duyarsız arama
```

**Paket Kurma:**

Bir veya daha fazla paketi kurmak için:

```bash
sudo pkg install htop screen vim
```

Onay istenecektir (`-y` ile atlanabilir).

**Paket Bilgisi Gösterme:**

Kurulu veya depodaki bir paket hakkında detaylı bilgi almak için:

```bash
pkg info htop
```

**Kurulu Paketleri Listeleme:**

Sistemde kurulu tüm paketleri listelemek için:

```bash
pkg info | less
```

**Paketleri Güncelleme:**

Kurulu tüm paketleri depolardaki en son sürümlerine yükseltmek için:

```bash
sudo pkg upgrade
```

**Paket Kaldırma:**

Bir veya daha fazla paketi kaldırmak için:

```bash
sudo pkg delete htop
```

**Gereksiz Bağımlılıkları Kaldırma:**

Artık başka hiçbir paketin ihtiyaç duymadığı bağımlılıkları kaldırmak için:

```bash
sudo pkg autoremove
```

**Paket Denetimi (Güvenlik Açıkları):**

Kurulu paketlerde bilinen güvenlik açıklarını kontrol etmek için:

```bash
sudo pkg audit -F # Önce veritabanını günceller, sonra denetler
```

**İndirilen Paket Önbelleğini Temizleme:**

`pkg` tarafından indirilen eski paket dosyalarını temizlemek için:

```bash
sudo pkg clean
```

**Hangi Paketin Bir Dosyayı Sağladığını Bulma:**

```bash
pkg which /usr/local/bin/htop
```

## Ports mu, pkg mi?

* **`pkg`:** Hızlı kurulum, kolay yönetim, derleme gerektirmez. Çoğu kullanıcı ve sunucu için genellikle yeterli ve **önerilen** yöntemdir.
* **Ports:** Derleme seçeneklerini özelleştirme ihtiyacı olduğunda, belirli bir yama uygulamak gerektiğinde veya `pkg` deposunda bulunmayan/çok eski olan bir yazılımı kurmak için kullanılır. Daha fazla kontrol sunar ancak daha yavaş ve zahmetlidir.

İki sistem bir arada kullanılabilir, ancak dikkatli olmak gerekir. Genellikle `pkg` ile kurulan bir paketi Ports ile güncellemek veya tersi sorunlara yol açabilir. Birincil yöntem olarak birini seçmek ve diğerini sadece gerektiğinde kullanmak daha iyi bir yaklaşımdır.


# Güncelleme Teknikleri

FreeBSD'de güncellemeler iki ana kategoriye ayrılır: **Temel Sistem Güncellemeleri** (işletim sisteminin çekirdeği ve ana kullanıcı alanı araçları) ve **Paket Güncellemeleri** (kurulan üçüncü parti yazılımlar). Bu iki tür güncelleme için farklı araçlar kullanılır.

## 1. Temel Sistem Güncellemeleri (`freebsd-update`)

`freebsd-update` aracı, FreeBSD temel sistemini (kernel ve world) resmi FreeBSD sunucularından indirilen ikili (binary) yamalar veya dosyalar aracılığıyla güncellemek için kullanılır. Kaynak koddan derleme yapmaya gerek kalmadan sistemi güncel tutmanın standart ve önerilen yoludur.

**Güvenlik Yamalarını ve Küçük Güncellemeleri Alma/Uygulama:**

Bu, sisteminizi mevcut sürüm dalındaki (örn. 13.2-RELEASE) en son yama seviyesine getirir.

```bash
# Güncellemeleri kontrol et ve indir
sudo freebsd-update fetch

# İndirilen güncellemeleri kur
sudo freebsd-update install 
```

`freebsd-update install` komutu çekirdek güncellemeleri içeriyorsa, genellikle sistemi yeniden başlatmanızı (`sudo shutdown -r now`) ve ardından komutu *tekrar* çalıştırmanızı isteyecektir (kullanıcı alanı güncellemelerini tamamlamak için).

**Yeni Bir Küçük Sürüme (Minor Version) Yükseltme:**

Örneğin, 13.1-RELEASE'den 13.2-RELEASE'e yükseltmek için:

```bash
# Hedef sürümü belirterek yükseltme işlemini başlat
sudo freebsd-update -r 13.2-RELEASE upgrade

# Komut, indirilecek değişiklikleri ve potansiyel olarak manuel müdahale 
# gerektirebilecek yapılandırma dosyası farklılıklarını gösterecektir.
# Dikkatlice inceleyin ve onaylayın (genellikle 'yes' ile).
# ... (İndirme ve hazırlık süreci) ...

# İlk kurulum adımını çalıştır (genellikle yeni çekirdek kurulur)
sudo freebsd-update install

# Sistemi yeniden başlat
sudo shutdown -r now

# Yeniden başlattıktan sonra, kalan güncellemeleri kur
sudo freebsd-update install 
```

**Yeni Bir Ana Sürüme (Major Version) Yükseltme:**

Örneğin, 12.4-RELEASE'den 13.2-RELEASE'e yükseltmek için süreç küçük sürüm yükseltmeye benzer, ancak daha fazla değişiklik içerir ve daha dikkatli olunmalıdır:

```bash
# Hedef sürümü belirterek yükseltme işlemini başlat
sudo freebsd-update -r 13.2-RELEASE upgrade

# ... (Değişiklikleri incele, onayla, indir) ...

# İlk kurulum (yeni çekirdek)
sudo freebsd-update install

# Sistemi yeniden başlat
sudo shutdown -r now

# Kalan güncellemeleri kur (ilk adım)
sudo freebsd-update install 

# ÖNEMLİ: Ana sürüm yükseltmesinden sonra, kurulan tüm paketlerin
# yeni sürümle uyumlu hale getirilmesi gerekir. Bu genellikle 
# 'pkg upgrade' ile yapılır (bkz. Paket Güncellemeleri).
sudo pkg bootstrap -f # pkg'nin kendisini güncellemek gerekebilir
sudo pkg upgrade -y

# Paketler güncellendikten sonra, eski kütüphaneleri vb. kaldırmak için
# freebsd-update install komutunu SON KEZ çalıştırın.
sudo freebsd-update install 
```

Ana sürüm yükseltmeleri öncesinde mutlaka FreeBSD Sürüm Notları'nı (Release Notes) ve Errata'yı okumak, önemli verileri yedeklemek şiddetle tavsiye edilir.

## 2. Paket Güncellemeleri (`pkg upgrade`)

Sisteminize `pkg install` ile veya Ports üzerinden kurduğunuz üçüncü parti yazılımları (paketleri) güncellemek için `pkg upgrade` komutu kullanılır. Bu komut, yapılandırılmış depolardaki en son paket sürümlerini kontrol eder ve kurulu paketleri günceller.

```bash
# Önce paket kataloğunu güncelle (isteğe bağlı ama önerilir)
sudo pkg update

# Kurulu tüm paketleri en son sürümlerine yükselt
sudo pkg upgrade 
```

Onay istenecektir (`-y` ile atlanabilir).

Eğer paketleri Ports Koleksiyonu'ndan derleyerek kurduysanız, `pkg upgrade` yine de çalışabilir (eğer güncel binary paketler depoda mevcutsa). Ancak, derleme seçenekleriniz özel ise veya binary paket yoksa, Ports ağacını güncelledikten sonra (`portsnap fetch update` veya `git pull`) ilgili port dizininde `make deinstall install clean` yapmak veya `portmaster -a` gibi bir araç kullanmak gerekebilir. Yine de çoğu durumda `pkg upgrade` yeterli olacaktır.

## 3. Ports Ağacını Güncelleme (`portsnap`)

Eğer yazılımları kaynak koddan derlemek için Ports Koleksiyonu'nu kullanıyorsanız, `/usr/ports` dizinindeki ağacı güncel tutmanız gerekir. Bu işlem, kurulu paketleri *güncellemez*, sadece yeni yazılımları derlemek için gerekli olan "tarifleri" (Makefile vb.) günceller.

```bash
# Ports ağacını güncelle
sudo portsnap fetch update
```

Bu komut, sadece Ports kullanıyorsanız düzenli olarak çalıştırılmalıdır. Sadece `pkg` kullanıyorsanız bu adıma genellikle gerek yoktur.

Özetle:

* Temel FreeBSD sistemi için: `sudo freebsd-update fetch` ve `sudo freebsd-update install`.
* Kurulu paketler için: `sudo pkg update` ve `sudo pkg upgrade`.
* Ports Koleksiyonu'nun kendisi için (eğer kullanılıyorsa): `sudo portsnap fetch update`.


# Network Ayarları

FreeBSD'de ağ yapılandırması genellikle `/etc/rc.conf` dosyası üzerinden yapılır. Bu dosya, sistem başlangıcında çalıştırılacak servisleri ve ağ arayüzleri gibi temel sistem parametrelerini tanımlar. DNS sunucu adresleri ise `/etc/resolv.conf` dosyasında belirtilir.

## `/etc/rc.conf` ile Yapılandırma

`/etc/rc.conf` dosyasına eklenen veya değiştirilen satırlar, sistem başlangıcında veya `netif` servisi yeniden başlatıldığında uygulanır.

**Ağ Arayüzlerini Listeleme:**\
Sistemdeki ağ arayüzlerini görmek için `ifconfig` komutu kullanılır:

```bash
ifconfig -a
```

**DHCP ile Otomatik Yapılandırma:**\
Bir ağ arayüzünün (örneğin `em0`) DHCP kullanarak otomatik olarak yapılandırılması için `/etc/rc.conf` dosyasına şu satır eklenir:

```bash
ifconfig_em0="DHCP" 
```

Birden fazla arayüz varsa, her biri için ayrı bir satır eklenir.

**Statik IP Adresi ile Yapılandırma:**`em0` arayüzüne statik bir IP adresi, alt ağ maskesi ve varsayılan ağ geçidi atamak için `/etc/rc.conf` dosyasına aşağıdaki gibi satırlar eklenir:

```bash
# em0 arayüzü için statik IP ayarları
ifconfig_em0="inet 192.168.1.100 netmask 255.255.255.0" 
# Varsayılan ağ geçidi
defaultrouter="192.168.1.1" 
```

* `ifconfig_<arayüz_adı>`: Belirtilen arayüz için yapılandırma satırını başlatır.
* `inet <ip_adresi>`: IPv4 adresini belirtir.
* `netmask <alt_ağ_maskesi>`: Alt ağ maskesini belirtir. Alternatif olarak CIDR notasyonu da kullanılabilir: `inet 192.168.1.100/24`.
* `defaultrouter`: Sistemin varsayılan ağ geçidini (router) tanımlar.

**Birden Fazla IP Adresi (Alias):**\
Bir arayüze birden fazla IP adresi atamak için `alias` kullanılır:

```bash
ifconfig_em0="inet 192.168.1.100 netmask 255.255.255.0"
ifconfig_em0_alias0="inet 192.168.1.101 netmask 255.255.255.0"
ifconfig_em0_alias1="inet 10.0.0.5 netmask 255.0.0.0"
defaultrouter="192.168.1.1"
```

**IPv6 Yapılandırması:**\
Statik IPv6 adresi ve SLAAC (StateLess Address AutoConfiguration) için:

```bash
# IPv6'yı etkinleştir
ipv6_enable="YES" 
# Statik IPv6 adresi (em0 için)
ifconfig_em0_ipv6="inet6 2001:db8:cafe::100 prefixlen 64" 
# SLAAC'ı etkinleştir (em0 için)
ifconfig_em0_ipv6="inet6 accept_rtadv" 
# Varsayılan IPv6 ağ geçidi
ipv6_defaultrouter="2001:db8:cafe::1" 
```

## DNS Ayarları (`/etc/resolv.conf`)

DNS sunucu adresleri `/etc/resolv.conf` dosyasında tanımlanır. Bu dosya genellikle DHCP istemcisi tarafından otomatik olarak güncellenir, ancak statik yapılandırmada manuel olarak düzenlenmesi gerekir.

```
search example.com # İsteğe bağlı: Alan adı arama listesi
nameserver 8.8.8.8   # Birincil DNS sunucusu
nameserver 8.8.4.4   # İkincil DNS sunucusu
```

## Değişiklikleri Uygulama

`/etc/rc.conf` dosyasında yapılan değişikliklerin geçerli olması için genellikle `netif` servisini yeniden başlatmak gerekir:

```bash
sudo service netif restart
```

Veya sadece belirli bir arayüzü yeniden başlatmak için:

```bash
sudo service netif restart em0
```

Sistemi yeniden başlatmak da (`sudo shutdown -r now`) ayarların uygulanmasını sağlar.

`/etc/resolv.conf` dosyasında yapılan değişiklikler genellikle anında geçerli olur.

## Geçici Ayarlar (`ifconfig`)

`ifconfig` komutu, çalışan sistem üzerinde ağ arayüzlerini geçici olarak yapılandırmak için de kullanılabilir. Bu ayarlar sistem yeniden başlatıldığında kaybolur.

```bash
# em0'a geçici IP ve maske ata
sudo ifconfig em0 inet 192.168.1.150 netmask 255.255.255.0

# Geçici varsayılan ağ geçidi ekle (route komutu ile)
sudo route add default 192.168.1.1

# Arayüzü kapat
sudo ifconfig em0 down

# Arayüzü aç
sudo ifconfig em0 up 
```

FreeBSD'nin ağ yapılandırması `/etc/rc.conf` merkezli yapısıyla oldukça basit ve güçlüdür. Detaylı bilgi ve diğer seçenekler için `rc.conf(5)` ve `ifconfig(8)` man sayfalarına bakılabilir.


# Arch Linux

Arch Linux, hafif, esnek ve basit ("Keep It Simple, Stupid" - KISS) olmayı hedefleyen, bağımsız olarak geliştirilen bir Linux dağıtımıdır. Sürekli güncellenen (rolling release) bir model kullanır, yani belirli sürüm yükseltmeleri yerine sistem sürekli olarak en son paketlerle güncellenir. Arch Linux, kullanıcısına sistem üzerinde tam kontrol vermeyi amaçlar ve bu nedenle kurulum süreci diğer birçok dağıtıma göre daha manuel ve komut satırı odaklıdır.

**ÖNEMLİ UYARI:** Arch Linux kurulum süreci detaylıdır ve zamanla değişiklik gösterebilir. Bu bölümdeki adımlar genel bir rehber niteliğindedir. **Her zaman en güncel ve doğru bilgiler için resmi Arch Wiki Kurulum Kılavuzu'na başvurmanız şiddetle tavsiye edilir:** <https://wiki.archlinux.org/title/Installation_guide>

## Başlangıç ve Kurulum Ortamı

Arch Linux kurulumu, güncel bir kurulum medyasından (USB bellek veya CD/DVD) sistemi başlatarak başlar. Kurulum medyası boot edildiğinde, genellikle doğrudan bir komut satırı (root shell) açılır. Kurulumun büyük bölümü bu komut satırı üzerinden gerçekleştirilir.

## İnternet Bağlantısı Kurulumu

Kurulum için aktif bir internet bağlantısı gereklidir (paketleri indirmek için).

1. **Bağlantıyı Kontrol Et:** Kurulum ortamı genellikle kablolu bağlantılar için `dhcpcd` servisini otomatik başlatır. Bağlantıyı test edin:

   ```bash
   ping archlinux.org -c 3 
   ```
2. **Wi-Fi Bağlantısı:**
   * Arayüz adını bulun: `iwctl device list`
   * `iwctl` interaktif aracını kullanarak ağları tarayın, bağlanın ve şifreyi girin:

     ```bash
     iwctl
     # iwctl içinde:
     # station <cihaz_adı> scan
     # station <cihaz_adı> get-networks
     # station <cihaz_adı> connect <SSID> 
     # ... (şifre istenir) ...
     # exit 
     ```
   * Alternatif olarak `wifi-menu` (eğer mevcutsa) veya NetworkManager (`nmtui`) gibi araçlar da kullanılabilir.
3. **Statik IP (Gerekirse):** Kablolu veya kablosuz bağlantı için statik IP gerekiyorsa, `ip` komutları ile geçici olarak ayarlayabilir veya `systemd-networkd`, NetworkManager gibi araçların yapılandırma dosyalarını düzenleyebilirsiniz (kurulum ortamında bu genellikle gerekli olmaz, asıl sistem kurulduktan sonra yapılır).

İnternet bağlantısı sağlandıktan sonra sistem saatini NTP ile senkronize etmek iyi bir fikirdir:

```bash
timedatectl set-ntp true
```

## Diskleri Hazırlama

1. **Diskleri Listele:** Mevcut diskleri ve bölümleri görmek için:

   ```bash
   lsblk
   # veya fdisk -l
   ```
2. **Bölümlendirme:** Diski bölümlendirmek için `fdisk`, `cfdisk` (metin arayüzü) veya `parted` gibi araçları kullanın.

   * **BIOS/MBR Sistemler:** Genellikle bir kök (`/`) bölümü ve bir swap bölümü yeterlidir.
   * **UEFI/GPT Sistemler:**
     * **EFI Sistem Bölümü (ESP):** FAT32 olarak biçimlendirilmiş, genellikle 200-512MB boyutunda, `/boot` veya `/efi` altına bağlanacak bir bölüm gereklidir.
     * **Kök Bölümü (`/`):** Sistemin kurulacağı ana bölüm (örn. ext4, xfs, btrfs).
     * **Swap:** Ayrı bir bölüm veya swap dosyası olarak oluşturulabilir.
     * **(İsteğe Bağlı) Diğer Bölümler:** `/home` gibi ayrı bölümler oluşturulabilir.

   ```bash
   # Örnek: cfdisk ile /dev/sda üzerinde bölümlendirme
   cfdisk /dev/sda 
   ```

   `cfdisk` içinde yeni bölümler oluşturun, boyutlarını ayarlayın, türlerini belirleyin (Linux filesystem, Linux swap, EFI System) ve değişiklikleri yazın (`[Write]`).
3. **Dosya Sistemlerini Oluşturma:** Oluşturulan bölümleri biçimlendirin:

   ```bash
   # Kök bölümü için (örnek: ext4)
   mkfs.ext4 /dev/sda2 

   # EFI Sistem Bölümü için (FAT32)
   mkfs.fat -F32 /dev/sda1 

   # Swap bölümü için (varsa)
   mkswap /dev/sda3 
   ```
4. **Bölümleri Bağlama (Mount):** Dosya sistemlerini kurulacak sistemin hiyerarşisine göre bağlayın. Kök bölümü `/mnt` altına bağlanmalıdır.

   ```bash
   # Kök bölümünü bağla
   mount /dev/sda2 /mnt

   # Diğer bölümleri oluştur ve bağla (örnek: /home)
   # mkdir /mnt/home
   # mount /dev/sdaX /mnt/home 

   # EFI Sistem Bölümünü bağla (UEFI için)
   mkdir -p /mnt/boot # veya /mnt/efi
   mount /dev/sda1 /mnt/boot # veya /mnt/efi

   # Swap'ı etkinleştir (varsa)
   swapon /dev/sda3 
   ```

## Temel Sistemi Kurma (`pacstrap`)

`pacstrap` betiği, belirtilen bağlama noktasına (`/mnt`) temel Arch Linux paketlerini ve isteğe bağlı diğer paketleri indirip kurar.

```bash
# Temel sistemi, Linux çekirdeğini ve yaygın firmware'leri kur
pacstrap /mnt base linux linux-firmware

# İsteğe bağlı: Metin düzenleyici, ağ yönetim aracı gibi ek paketler
pacstrap /mnt vim networkmanager 
```

`base-devel` grubu, AUR paketlerini derlemek için genellikle gereklidir ve bu aşamada veya daha sonra kurulabilir.

## Sistemi Yapılandırma

1. **fstab Oluşturma:** Bağlı dosya sistemleri için `/etc/fstab` dosyasını oluşturun. UUID kullanmak genellikle daha güvenilirdir.

   ```bash
   genfstab -U /mnt >> /mnt/etc/fstab
   ```

   Oluşturulan `/mnt/etc/fstab` dosyasını kontrol edin (`cat /mnt/etc/fstab`).
2. **chroot:** Kurulan sisteme `chroot` ile geçiş yapın:

   ```bash
   arch-chroot /mnt
   ```

   Bundan sonraki komutlar yeni kurulan sistem içinde çalışacaktır.
3. **Zaman Dilimi (Timezone):**

   ```bash
   # Örnek: İstanbul için
   ln -sf /usr/share/zoneinfo/Europe/Istanbul /etc/localtime
   # Donanım saatini UTC'ye göre ayarla (önerilen)
   hwclock --systohc --utc 
   ```
4. **Yerelleştirme (Localization):**
   * `/etc/locale.gen` dosyasını düzenleyerek istediğiniz yerel ayarların (örn. `en_US.UTF-8 UTF-8`, `tr_TR.UTF-8 UTF-8`) başındaki `#` işaretini kaldırın.
   * Yerel ayarları oluşturun:

     ```bash
     locale-gen
     ```
   * Sistem dilini ayarlayın (`/etc/locale.conf`):

     ```bash
     echo LANG=en_US.UTF-8 > /etc/locale.conf
     # veya Türkçe için: echo LANG=tr_TR.UTF-8 > /etc/locale.conf
     ```
   * (İsteğe bağlı) Klavye düzenini ayarlayın (`/etc/vconsole.conf`):

     ```bash
     # Örnek: Türkçe F klavye için
     # echo KEYMAP=trf > /etc/vconsole.conf 
     ```
5. **Ağ Yapılandırması:**
   * **Hostname:** Makine adını ayarlayın (`/etc/hostname`):

     ```bash
     echo myarchlinux > /etc/hostname
     ```
   * **(İsteğe bağlı) Hosts dosyası:** `/etc/hosts` dosyasını düzenleyerek localhost ve makine adını ekleyin:

     ```
     127.0.0.1   localhost
     ::1         localhost
     127.0.1.1   myarchlinux.localdomain myarchlinux 
     ```
   * **Ağ Yönetim Servisini Etkinleştirme:** Kurulum sırasında `pacstrap` ile kurduğunuz ağ yönetim aracının servisini etkinleştirin (örn. NetworkManager):

     ```bash
     systemctl enable NetworkManager 
     # veya dhcpcd için: systemctl enable dhcpcd
     # veya systemd-networkd için: systemctl enable systemd-networkd
     ```
6. **Root Şifresi:** Root kullanıcısı için bir şifre belirleyin:

   ```bash
   passwd
   ```
7. **Önyükleyici (Bootloader):** Sistemin başlayabilmesi için bir önyükleyici kurulmalıdır.

   * **GRUB (BIOS veya UEFI):**

     ```bash
     pacman -S grub # Gerekliyse os-prober'ı da kurun
     # BIOS için:
     # grub-install --target=i386-pc /dev/sda 
     # UEFI için (ESP /boot altına bağlıysa):
     grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB
     # Yapılandırma dosyasını oluştur
     grub-mkconfig -o /boot/grub/grub.cfg 
     ```
   * **systemd-boot (Sadece UEFI):** Daha basit bir alternatiftir.

     ```bash
     bootctl --path=/boot install # ESP'nin /boot altına bağlı olduğunu varsayar
     # /boot/loader/loader.conf ve /boot/loader/entries/arch.conf dosyalarını oluştur/düzenle
     ```

   Resmi Arch Wiki, önyükleyici kurulumu için detaylı bilgi sağlar.

## Kurulumu Tamamlama

1. **chroot'tan Çık:**

   ```bash
   exit
   ```
2. **Bölümleri Ayır (Unmount):**

   ```bash
   umount -R /mnt 
   ```
3. **Yeniden Başlat:**

   ```bash
   reboot
   ```

   Kurulum medyasını çıkarın ve yeni kurulan Arch Linux sisteminizi başlatın. İlk açılışta kullanıcı adı olarak `root` ve belirlediğiniz şifre ile giriş yapın.

## Kurulum Sonrası Adımlar

* **Kullanıcı Oluşturma:** Normal bir kullanıcı hesabı oluşturun:

  ```bash
  useradd -m -G wheel kullanıcı_adı
  passwd kullanıcı_adı
  ```
* **Sudo Kurulumu:** `sudo` paketini kurun (`pacman -S sudo`) ve `visudo` komutu ile `/etc/sudoers` dosyasını düzenleyerek `%wheel ALL=(ALL:ALL) ALL` satırının başındaki `#` işaretini kaldırın. Bu, `wheel` grubundaki kullanıcıların `sudo` kullanmasını sağlar.
* **Paketleri Güncelleme:** Sistemi tamamen güncelleyin:

  ```bash
  sudo pacman -Syu
  ```
* **Grafik Arayüzü (İsteğe Bağlı):** Masaüstü ortamı (GNOME, KDE, XFCE vb.) ve Xorg veya Wayland görüntü sunucusunu kurun.
* **AUR Yardımcıları (İsteğe Bağlı):** Arch User Repository (AUR)'dan paket kurmayı kolaylaştırmak için `yay` veya `paru` gibi bir yardımcı kurun.

Arch Linux kurulumu, sistemi temelden anlamak için harika bir yoldur, ancak dikkat ve sabır gerektirir. Her adımda Arch Wiki'ye başvurmaktan çekinmeyin.


# pacman ve AUR

Arch Linux'un paket yöneticisi **pacman**, sistemin en belirgin özelliklerinden biridir. `pacman`, ikili (binary) paketleri resmi depolardan (repositories) veya yerel dosyalardan kurmayı, güncellemeyi, kaldırmayı ve sorgulamayı sağlar. Bağımlılıkları otomatik olarak yönetir ve sistemi güncel tutmayı kolaylaştırır. Arch Linux paketleri genellikle `.pkg.tar.zst` (veya eski `.pkg.tar.xz`) formatındadır.

`pacman`'in ana yapılandırma dosyası `/etc/pacman.conf`'tur. Bu dosyada aktif depolar, genel seçenekler (renkli çıktı, paralel indirmeler vb.) ve yoksayılacak paketler gibi ayarlar bulunur.

## `pacman` Temel Komutları

**Paket Listelerini ve Sistemi Güncelleme:**

Arch Linux sürekli güncellenen (rolling release) bir model kullandığı için, sistemi düzenli olarak güncellemek önemlidir. Paket kurmadan önce de genellikle sistemin güncellenmesi tavsiye edilir.

* **`-Syyu`**: Yerel paket veritabanını sunucularla zorla senkronize eder (`yy`) ve kurulu tüm paketleri günceller (`u`). Genellikle ayna (mirror) listesi değiştirildikten sonra kullanılır.
* **`-Syu`**: Yerel paket veritabanını (gerekirse) senkronize eder (`y`) ve kurulu tüm paketleri günceller (`u`). **En sık kullanılan güncelleme komutudur.**

  ```bash
  sudo pacman -Syu 
  ```
* **`-Sy`**: Sadece yerel paket veritabanını senkronize eder. Paket kurmadan sadece `-Sy` çalıştırmak, güncel olmayan bir sistemle yeni paket listesi arasında uyumsuzluklara (partial upgrades) yol açabileceğinden **kesinlikle önerilmez**.

**Paket Kurma:**

* **`-S <paket_adı>`**: Belirtilen paketi (ve bağımlılıklarını) depolardan indirip kurar.

  ```bash
  sudo pacman -S htop vim screen
  ```
* **`-U <dosya_adı.pkg.tar.zst>`**: Yerel bir paket dosyasını (ve `pacman`'in bulabildiği bağımlılıklarını) kurar.

  ```bash
  sudo pacman -U ./indirilen-paket.pkg.tar.zst
  ```

**Paket Kaldırma:**

* **`-R <paket_adı>`**: Belirtilen paketi kaldırır, ancak bağımlılıklarına dokunmaz.
* **`-Rs <paket_adı>`**: Belirtilen paketi ve artık başka hiçbir paket tarafından gereksinim duyulmayan bağımlılıklarını kaldırır (`s`: recursive). **Genellikle tercih edilen kaldırma yöntemidir.**

  ```bash
  sudo pacman -Rs htop
  ```
* **`-Rns <paket_adı>`**: `-Rs` gibidir, ancak kaldırırken yapılandırma dosyalarını da siler (`n`: nosave).
* **`-Rsc <paket_adı>`**: Paketi, bağımlılıklarını ve bu pakete bağımlı olan diğer tüm paketleri kaldırır (`c`: cascade). **Dikkatli kullanılmalıdır!**
* **`-Rdd <paket_adı>`**: Bağımlılık kontrollerini tamamen yoksayarak paketi kaldırır. **Çok tehlikelidir ve genellikle kullanılmamalıdır!**

**Paket Sorgulama:**

* **`-Ss <anahtar_kelime>`**: Depolarda paket adı veya açıklamasında arama yapar (`s`: search).

  ```bash
  pacman -Ss network manager
  ```
* **`-Qs <anahtar_kelime>`**: Kurulu paketler içinde arama yapar.
* **`-Si <paket_adı>`**: Depodaki bir paket hakkında detaylı bilgi gösterir (`i`: info).
* **`-Qi <paket_adı>`**: Kurulu bir paket hakkında detaylı bilgi gösterir.
* **`-Ql <paket_adı>`**: Kurulu bir paketin içerdiği dosyaları listeler (`l`: list).
* **`-Qo <dosya_yolu>`**: Belirtilen dosyanın hangi pakete ait olduğunu gösterir (`o`: owns).

  ```bash
  pacman -Qo /usr/bin/htop
  ```
* **`-Qdt`**: Yetim (orphan) paketleri, yani başka hiçbir paket tarafından gereksinim duyulmayan bağımlılıkları listeler (`d`: dependencies, `t`: unrequired). Bunlar genellikle `sudo pacman -Rns $(pacman -Qdtq)` komutuyla temizlenebilir (`q`: quiet, sadece isimleri listeler).
* **`-Qe`**: Açıkça (manuel olarak) kurulmuş paketleri listeler. Bağımlılık olarak kurulanları göstermez (`e`: explicit).
* **`-Qk <paket_adı>`**: Kurulu bir paketin dosyalarının bütünlüğünü kontrol eder (`k`: check).

## AUR (Arch User Repository)

AUR (Arch User Repository), Arch Linux'un resmi depolarında bulunmayan binlerce paketin topluluk tarafından sağlanan yapılandırma betiklerini (PKGBUILD) içeren bir depodur. AUR'daki paketler genellikle kaynak koddan derlenir.

**PKGBUILD:** Bir paketin nasıl indirileceğini, derleneceğini ve paketleneceğini tanımlayan bir kabuk betiğidir.

**makepkg:** Bir `PKGBUILD` dosyasını kullanarak paketi derleyen ve `.pkg.tar.zst` formatında paket oluşturan araçtır (`pacman` ile birlikte gelir).

**AUR Yardımcıları (AUR Helpers):** AUR'dan paket arama, indirme, derleme ve kurma işlemlerini otomatikleştiren araçlardır (örn. `yay`, `paru`). `pacman`'in kendisi doğrudan AUR ile etkileşim kurmaz.

**Uyarı:** AUR paketleri topluluk tarafından sağlandığı için resmi depolar kadar denetlenmezler. Kurmadan önce `PKGBUILD` dosyasını incelemek güvenlik açısından iyi bir pratiktir.

**AUR Yardımcısı Kurulumu (Örnek: `yay`)**

Bir AUR yardımcısını kurmak için genellikle önce onun `PKGBUILD` dosyasını AUR web sitesinden bulup manuel olarak kurmanız gerekir (bootstrap). `yay` popüler bir yardımcıdır:

1. **Gerekli Paketleri Kur:** `base-devel` grubu ve `git` genellikle gereklidir.

   ```bash
   sudo pacman -Syu --needed base-devel git
   ```
2. **`yay` deposunu klonla:** AUR'dan `yay`'ın PKGBUILD'ini içeren git deposunu klonlayın (genellikle geçici bir dizine).

   ```bash
   # Örnek: /tmp dizinine klonlama
   cd /tmp
   git clone https://aur.archlinux.org/yay.git
   ```
3. **Derle ve Kur:** Klonlanan dizine girin ve `makepkg` ile paketi oluşturup kurun.

   ```bash
   cd yay
   makepkg -si
   ```

   * `m`: Eksik bağımlılıkları `pacman` ile kurar (make dependencies).
   * `s`: Kaynak kod bağımlılıklarını `pacman` ile kurar (sync dependencies).
   * `i`: Paket başarıyla derlenirse `pacman -U` ile kurar (install).

   `makepkg` işlemi sırasında PGP anahtarlarını içe aktarmanız istenebilir. Güvenilir anahtarları içe aktarmak için onay vermeniz gerekir.
4. **(İsteğe Bağlı) Temizlik:** Derleme dizinini silebilirsiniz.

   ```bash
   cd ..
   rm -rf yay
   ```

**AUR Yardımcısı Kullanımı (Örnek: `yay`)**

`yay` kurulduktan sonra, `pacman` komutlarına benzer şekilde hem resmi depolardan hem de AUR'dan paket yönetimi için kullanılabilir:

```bash
# AUR'da ve resmi depolarda paket ara
yay -Ss <anahtar_kelime>

# AUR'dan veya resmi depodan paket kur/güncelle
yay -S <paket_adı>

# Sistemi ve AUR paketlerini güncelle (pacman -Syu + AUR güncellemeleri)
yay -Syu 
# veya sadece:
yay 

# Kurulu paketleri kaldır (pacman -R komutlarını kullanır)
yay -Rns <paket_adı> 

# AUR paketlerini geliştirme sürümlerini de kontrol ederek güncelle
# yay -Syu --devel 
```

AUR, Arch Linux'un gücünü ve esnekliğini artıran önemli bir parçasıdır, ancak kullanırken dikkatli olmak gerekir.


# Network Ayarları

Arch Linux, ağ yapılandırması için kullanıcısına çeşitli seçenekler sunar. Kurulum sırasında veya sonrasında ihtiyaca göre farklı ağ yönetim araçları kurulup yapılandırılabilir. Yaygın kullanılan yöntemler şunlardır:

1. **systemd-networkd:** systemd ile entegre, genellikle sunucular ve basit yapılandırmalar için tercih edilen modern bir ağ yöneticisi.
2. **NetworkManager:** Hem masaüstü hem de sunucu ortamlarında popüler, tam özellikli bir ağ yöneticisi. Özellikle Wi-Fi ve mobil bağlantılar için kullanışlıdır.
3. **dhcpcd:** Basit bir DHCP istemcisi. Statik IP yapılandırması için de kullanılabilir ancak genellikle diğer araçlar kadar esnek değildir.
4. **netctl:** Arch Linux'a özgü, profil tabanlı bir ağ yönetim aracı (artık daha az yaygın).
5. **Manuel Yapılandırma:** `ip` komutları ve diğer düşük seviyeli araçlarla manuel yapılandırma (genellikle önerilmez).

**Önemli:** Bir ağ arayüzü (örn. `eth0`, `enp0s3`, `wlan0`) aynı anda sadece *bir* yönetim aracı tarafından kontrol edilmelidir. Örneğin, hem NetworkManager hem de systemd-networkd'yi aynı anda aynı arayüz için etkinleştirmek sorunlara yol açar.

## Metod 1: systemd-networkd

`systemd-networkd`, systemd'nin bir parçasıdır ve yapılandırması `/etc/systemd/network/` dizini altındaki `.network` uzantılı dosyalarla yapılır. DNS yönetimi için genellikle `systemd-resolved` servisi ile birlikte kullanılır.

**Yapılandırma Dosyaları:**

* **DHCP (Örnek: `/etc/systemd/network/20-wired.network`):**

  ```ini
  [Match]
  Name=en* # 'en' ile başlayan tüm kablolu arayüzlerle eşleşir

  [Network]
  DHCP=ipv4 
  ```
* **Statik IP (Örnek: `/etc/systemd/network/20-wired-static.network`):**

  ```ini
  [Match]
  Name=enp0s3 # Belirli bir arayüzle eşleşir

  [Network]
  Address=192.168.1.100/24
  Gateway=192.168.1.1
  DNS=8.8.8.8
  DNS=8.8.4.4
  ```

**Servisleri Etkinleştirme ve Başlatma:**

```bash
# systemd-networkd'yi etkinleştir ve başlat
sudo systemctl enable systemd-networkd.service
sudo systemctl start systemd-networkd.service

# systemd-resolved'u etkinleştir ve başlat (DNS için)
sudo systemctl enable systemd-resolved.service
sudo systemctl start systemd-resolved.service

# /etc/resolv.conf'un systemd-resolved tarafından yönetilmesi için link oluştur
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf 
```

## Metod 2: NetworkManager

NetworkManager, özellikle dinamik ortamlar ve kablosuz ağlar için popüler bir seçenektir. `nmtui` (metin arayüzü) ve `nmcli` (komut satırı) araçlarını sunar.

**Kurulum (Gerekirse):**

```bash
sudo pacman -S networkmanager
```

**Servisi Etkinleştirme ve Başlatma:**

```bash
sudo systemctl enable NetworkManager.service
sudo systemctl start NetworkManager.service
```

**NOT:** Eğer `dhcpcd` veya `systemd-networkd` gibi başka bir ağ servisi çalışıyorsa, NetworkManager'ı etkinleştirmeden önce onu durdurup devre dışı bırakmanız gerekir (`sudo systemctl stop <servis>`, `sudo systemctl disable <servis>`).

**Yapılandırma (`nmtui`):**\
Kullanımı en kolay yöntemlerden biridir. Terminalde çalıştırın:

```bash
sudo nmtui
```

Açılan menüden "Edit a connection" ile bağlantıları düzenleyebilir (statik IP, DHCP, DNS vb.), "Activate a connection" ile etkinleştirebilirsiniz.

**Yapılandırma (`nmcli`):**\
Komut satırı üzerinden daha detaylı kontrol sağlar. Örnekler için RHEL/CentOS bölümündeki [Network Ayarları (NetworkManager)](/temel-dagitimlar/centos/network-ayarlari) kısmına bakabilirsiniz. Komutlar Arch Linux üzerinde de geçerlidir.

## Metod 3: dhcpcd

Basit bir DHCP istemcisidir. Statik IP atamak için de kullanılabilir ancak genellikle NetworkManager veya systemd-networkd daha esnektir.

**Kurulum (Gerekirse):**`dhcpcd` genellikle temel kurulumda gelir.

**Servisi Etkinleştirme (Belirli Arayüz İçin):**

```bash
# Örnek: enp0s3 arayüzü için DHCP'yi etkinleştir ve başlat
sudo systemctl enable dhcpcd@enp0s3.service
sudo systemctl start dhcpcd@enp0s3.service 
```

**Statik IP Yapılandırması (`/etc/dhcpcd.conf`):**`/etc/dhcpcd.conf` dosyasının sonuna aşağıdaki gibi satırlar eklenerek statik IP ayarlanabilir:

```
interface enp0s3
static ip_address=192.168.1.100/24
static routers=192.168.1.1
static domain_name_servers=8.8.8.8 8.8.4.4
```

Değişiklik sonrası `dhcpcd` servisini yeniden başlatmak gerekir:

```bash
sudo systemctl restart dhcpcd@enp0s3.service 
# veya tüm dhcpcd servisleri için:
# sudo systemctl restart dhcpcd.service
```

Arch Linux'ta ağ yönetimi için hangi yöntemin seçileceği kullanıcının tercihine ve ihtiyacına bağlıdır. Genellikle NetworkManager veya systemd-networkd modern ve esnek çözümler sunar.


# Ortak Network Dosyaları

Her ne kadar dağıtımların network ayarlarını yaparken farklılıklar olduğunu gördüysek de, bazı dosyalar tüm sistemlerde aynı işlevi görmektedir. Bu bölümde bu dosyaları inceleyeceğiz.

## hostname

Sistemin kendi ismini bilmesi için düzenlenmesi gereken iki dosyadan biridir. `/etc/hostname` yolundadır. Bu dosyanın içinde tek satır bulunur.

```bash
eaydin@dixon ~ $ cat /etc/hostname
dixon
```

Bu dosyanın düzenlenmesi eskisi kadar önem arz etmemektedir, aşağıdaki dosyalar daha kritiktir.

## hosts

Sistemin adreslere karşılık isim tuttuğu dosyadır.

```bash
eaydin@dixon ~ $ cat /etc/hosts
127.0.0.1    localhost
127.0.1.1    dixon

94.103.47.66 test-centos1 
94.103.47.78 test-debian1

94.103.33.130 plugged.in
```

Yukarıdan görüleceği gibi, sistemin localhost'u tanıması için 127.0.0.1'e işaret etmesi gerekir. Benzer şekilde hostname'de tanımladığımız değer de burada belirtilmelidir.

Alttaki satırlar ise kullanıcının kendince yarattığı kısa yollardır. Burada gördüğünüz plugged.in değeri sitenin gerçek adresidir. `/etc/hosts` dosyasında yer alması, herhangi bir şekilde DNS'lerden alınan bilginin önüne geçilmesi anlamına gelir. Kısacası artık sistem üzerinde her program plugged.in adresine gitmek için 94.103.33.130 IP'sini kullanacaktır. Eğer buraya başka bir değer, örneğin 94.103.32.32 yazsaydık, sistem üzerinde her program plugged.in'e gidecekken DNS'lere bakmadan 94.103.32.32'ye yönlenecekti, ve veritech.net sayfası cevap verecekti.

host dosyası manual dosyasına erişmek için

```bash
man 5 hosts
```

## /etc/nsswitch.conf

Bu dosya, sistemin isim çözme (örneğin, ana bilgisayar adlarını IP adreslerine çevirme) gibi işlemler için hangi kaynakları (örn. `files` - `/etc/hosts`, `dns`) ve hangi sırayla kullanacağını belirler. Özellikle `hosts:` satırı önemlidir:

```
# Örnek /etc/nsswitch.conf satırı
hosts:      files dns myhostname
```

Bu satır, bir ana bilgisayar adı çözümlenirken önce `/etc/hosts` dosyasına (`files`), sonra DNS sunucularına (`dns`), sonra da sistemin kendi ana bilgisayar adına (`myhostname`) bakılacağını belirtir.

## /etc/resolv.conf

Bu dosya, sistemin alan adı çözümlemesi (DNS) için kullanacağı nameserver (DNS sunucusu) adreslerini ve alan adı arama listesini (search domain) tanımlamak için kullanılır.

**Ancak Dikkat:** Modern Linux sistemlerinde `/etc/resolv.conf` dosyası genellikle **doğrudan düzenlenmez**. Çoğu zaman bu dosya, NetworkManager veya `systemd-resolved` gibi ağ yönetim servisleri tarafından **otomatik olarak oluşturulur ve yönetilir**. Manuel olarak yapılan değişiklikler, servis yeniden başladığında veya ağ bağlantısı değiştiğinde kaybolabilir.

**Yapısı:**\
Eğer manuel olarak düzenleniyorsa veya otomatik olarak oluşturulduğunda, genellikle aşağıdaki gibi görünür:

```
# Otomatik olarak NetworkManager veya systemd-resolved tarafından oluşturulmuş olabilir
search example.com internal.example.com # Alan adı arama listesi
nameserver 8.8.8.8                     # Birincil DNS sunucusu
nameserver 8.8.4.4                     # İkincil DNS sunucusu
```

* `nameserver <IP_adresi>`: Kullanılacak DNS sunucusunun IP adresini belirtir. Genellikle birden fazla `nameserver` satırı bulunabilir (yedeklilik için).
* `search <alan_adı1> <alan_adı2> ...`: Tam olmayan ana bilgisayar adları çözümlenirken denenecek alan adlarının listesini belirtir. Örneğin, `ping server1` komutu çalıştırıldığında sistem önce `server1.example.com`'u, sonra `server1.internal.example.com`'u çözmeye çalışır.
* `domain <alan_adı>`: Sistemin yerel alan adını belirtir. `search` listesindeki ilk alan adı olarak davranır. Genellikle `search` veya `domain` direktiflerinden sadece biri kullanılır.

**Modern Sistemlerde Yönetim:**

* **NetworkManager:** DHCP'den alınan veya bağlantı ayarlarında statik olarak belirtilen DNS sunucularını kullanarak `/etc/resolv.conf` dosyasını (genellikle `systemd-resolved` aracılığıyla veya doğrudan) yönetir. DNS ayarlarını değiştirmek için `nmcli` veya `nmtui` kullanılmalıdır.
* **systemd-resolved:** Bu servis aktif olduğunda, `/etc/resolv.conf` genellikle `/run/systemd/resolve/stub-resolv.conf` dosyasına bir sembolik link olur. Bu `stub-resolv.conf` dosyası sadece `127.0.0.53` adresini içerir. Gerçek DNS sunucuları `systemd-resolved` tarafından yönetilir ve `resolvectl status` komutu ile görülebilir. DNS sunucuları `systemd-networkd` yapılandırması (`.network` dosyaları) veya NetworkManager aracılığıyla `systemd-resolved`'a iletilir.

Özetle, `/etc/resolv.conf` dosyasının içeriğini anlamak önemli olsa da, modern sistemlerde bu dosyayı doğrudan düzenlemek yerine, ağı yöneten servisin (NetworkManager, systemd-networkd) yapılandırma araçlarını kullanmak gerekir.

Detaylı bilgi için `resolv.conf(5)` ve `nsswitch.conf(5)` man sayfalarına bakılabilir.


# SSH

Uzaktaki sunucuları yönetmek için kullanılan en yaygın yöntemlerden birisi ssh kullanımıdır. SSH, Secure Shell'in kısaltmasıdır ve adı üzerinde, güvenli bir bağlantı sağlar. Bağlanmak istediğiniz noktada SSH Sunucu dinliyor olduğu sürece, ve sizin kullandığınız uçbirimde SSH İstemci bulunduğu sürece sunucunuza güvenli bağlantı yapmaya yarar.

Güvenliden kasıt, sunucu tarafında belirlenen kimlik doğrulama (authentication) yöntemi dışında, bağlantınızın başkaları tarafından dinlenmesini engellemek için mesajları kriptolu iletmesidir. Bu açıdan SSH, Telnet ve muadili programların ağ üzerinden güvensiz iletişim biçimlerine alternatif olarak geliştirilmiştir.

## Tarihçe

SSH 1995 yılında Finlandiya'da Tatu Ylönen tarafından geliştirildi ancak uzun süre açık kaynak olarak dağıtılmadı. Bunun üzerine 1999 yılında Björn Grönvall tarafından OSSH adı altında açık kaynak kodlu lisansı olan bir SSH versiyonu geliştirildi. Bu kodları kendi sistemine uyarlayıp kısa sürede hızla geliştiren OpenBSD geliştiricileri, bu versiyona [OpenSSH](http://www.openssh.com) ismini verdiler. Bugün kullandığınız hemen her sunucudaki SSH versiyonu OpenSSH'tır ve geliştirilmesi hala devam etmektedir.

OpenSSH her ne kadar çok yaygın olsa da, eski sürümleri hem modern SSHv2 protokolünü hem de artık güvensiz kabul edilen eski SSHv1 protokolünü destekleyebiliyordu. **Günümüzde SSHv1 protokolü kesinlikle kullanılmamalı ve tüm sunucu yapılandırmalarında devre dışı bırakılmalıdır.** Modern OpenSSH sürümleri genellikle varsayılan olarak SSHv1'i desteklemez veya devre dışı bırakır.

Bazı gömülü sistemlerde veya özel durumlarda, kaynak kullanımı daha düşük olan alternatif SSH sunucuları (örn. [Dropbear](https://matt.ucc.asn.au/dropbear/dropbear.html)) kullanılabilir, ancak OpenSSH standart ve en yaygın kullanılan çözümdür.

SSH Sunucuların bir listesine ve yapabildiklerine aşağıdaki Wikipedia sayfasından ulaşabilirsiniz.

<https://en.wikipedia.org/wiki/Comparison_of_SSH_servers>

![](http://imgs.xkcd.com/comics/im_an_idiot.png)

*Kaynak:* <https://xkcd.com/530/>


# Uzak Sunucuya Bağlanma

Komut satırından ssh ile bir sunucuya bağlanmak oldukça kolaydır.

```bash
eaydin@dixon ~ $ ssh 94.103.47.66
eaydin@94.103.47.66's password:
```

Yukarıdaki gibi bağlandığımızda sunucu şifre sormaktadır. Bir kullanıcı adı belirtmediğimiz için, mevcut kullanıcıyı parametre olarak göndermiştir. Oysa ki sunucuya **root** kullanıcısı ile bağlanmak istiyorduk.

```bash
eaydin@dixon ~ $ ssh root@94.103.47.66
root@94.103.47.66's password:
```

Bu noktada root şifresini girip sisteme bağlanabiliriz.

Bazı durumlarda ssh sunucusunun portu farklı olabilir. Bu, yaygın güvenlik önlemlerinden birisidir. Örneğin yukarıdaki sunucumuzun portu standart SSH portu olan 22 yerine 2291 olsaydı, aşağıdaki gibi bağlanabilirdik.

```bash
ssh root@94.103.47.66 -p 2291
```

**İpucu:** Sık bağlandığınız sunucular için kullanıcı adı, port, özel anahtar yolu gibi seçenekleri her seferinde yazmak yerine, kullanıcının kendi ev dizinindeki `~/.ssh/config` dosyasında tanımlayabilirsiniz. Bu dosya, bağlantı kısayolları ve özel ayarlar tanımlamak için çok kullanışlıdır.

Örnek `~/.ssh/config` dosyası:

```
Host testserver
    HostName 94.103.47.66
    User root
    Port 2291
    IdentityFile ~/.ssh/id_testserver_ed25519

Host anotherserver
    HostName domain.adı.com
    User myuser
    Port 22
```

Bu yapılandırma ile `ssh testserver` komutu otomatik olarak `ssh root@94.103.47.66 -p 2291 -i ~/.ssh/id_testserver_ed25519` komutuna genişleyecektir.

## Kimlik Doğrulama Yöntemini Seçme

Sunucuya şifreyle bağlanmak yerine, özel anahtarımızla da bağlanabiliriz. İlerleyen bölümlerde bunu nasıl yapacağımızı göreceğiz. Ama şimdilik anahtar yüklü bir sisteme bağlanırken kimlik doğrulama yöntemini nasıl seçeceğimizi görebiliriz.

Aşağıdaki yöntem, kimlik doğrulamada anahtarı gözardı edip, şifre girmeyi zorunlu hale getirmektedir.

```bash
eaydin@dixon ~ $ ssh -o PreferredAuthentications=password \
-o PubkeyAuthentication=no root@94.103.47.66
root@94.103.47.66's password:
```

Öte yandan, dökümanlarda yer almasa da, bir [stackexchange](http://stackexchange.com) kullanıcısının OpenSSH kodlarını incelerken dikkatini çeken "şifre sormayı zorlama" yöntemini sizinle paylaşmak istiyoruz:

```bash
eaydin@dixon ~ $ ssh root:@94.103.47.66
root:@94.103.47.66's password:
```

[*Kaynak*](http://unix.stackexchange.com/a/124582)

Yukarıdaki yöntem, 2015 tarihinden itibaren çalışmamaya başlamış olsa da, bazı programlarda dokümante edilmemiş özelliklerin barınabileceğini göstermek için iyi bir örnek teşkil ediyor.

Aşağıdaki yöntemleyse, ayar dosyamızda belirilen ssh anahtarı dışında bir anahtarla bağlanabilmenin yolu görülmektedir.

```bash
eaydin@dixon ~ $ ssh -i /media/ssh_keys/eaydin_id_rsa root@94.103.47.66
```

## Strict Host Key Checking

Eğer bir sunucuya ilk kez bağlanıyorsanız, genellikle aşağıdaki gibi bir soruyla karşılaşırsınız.

```bash
eaydin@dixon ~ $ ssh root:@94.103.47.66
The authenticity of host '94.103.47.66 (94.103.47.66)' can't be established.
RSA key fingerprint is c2:54:d7:77:57:76:a1:78:f8:82:8b:48:de:89:71:c5.
Are you sure you want to continue connecting (yes/no)?
```

Burada SSH istemcisi, daha önce bağlanmadığınız bu sunucunun kimliğini (`94.103.47.66`) sunduğu genel anahtarın parmak izi (fingerprint) ile birlikte size gösterir. Bu mekanizmanın amacı, ortadaki adam (Man-in-the-Middle - MitM) saldırılarını önlemektir. İlk bağlantıda sunucunun parmak izini doğrulamanız (örneğin sunucu yöneticisinden teyit alarak) ve `yes` diyerek kabul etmeniz beklenir. Kabul ettiğinizde, sunucunun adresi ve genel anahtarı sizin `~/.ssh/known_hosts` dosyanıza kaydedilir.

**Not:** Örnekte RSA anahtarı gösterilmiştir. Modern SSH sunucuları genellikle daha güvenli ve performanslı olan Ed25519 veya ECDSA anahtarlarını tercih eder ve sunar. Parmak izi formatı da anahtar türüne göre değişebilir (örn. SHA256 tabanlı).

Ancak daha sonra bu soruyu sormaz, çünkü artık RSA parmak izini kenara not etmiştir SSH.

```bash
eaydin@dixon ~ $ ssh root:@94.103.47.66
The authenticity of host '94.103.47.66 (94.103.47.66)' can't be established.
RSA key fingerprint is c2:54:d7:77:57:76:a1:78:f8:82:8b:48:de:89:71:c5.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '94.103.47.66' (RSA) to the list of known hosts.
root:@94.103.47.66's password
```

İlerleyen zamanlarda aynı sunucuya tekrar bağlanmaya çalıştığınızda, SSH istemcisi sunucudan gelen genel anahtarı `known_hosts` dosyanızdaki kayıtlı anahtarla karşılaştırır. Eğer anahtarlar eşleşmezse (sunucu yeniden kurulmuş olabilir, anahtarı değişmiş olabilir veya gerçekten bir MitM saldırısı olabilir), SSH bağlantıyı durdurur ve aşağıdaki gibi bir uyarı verir:

```bash
eaydin@dixon ~ $ ssh root:@94.103.47.66
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
c2:54:d7:77:57:76:a1:78:f8:82:8b:48:de:89:71:c5.
Please contact your system administrator.
Add correct host key in /home/eaydin/.ssh/known_hosts to get rid of this message.
Offending RSA key in /home/eaydin/.ssh/known_hosts:1
  remove with: ssh-keygen -f "/home/eaydin/.ssh/known_hosts" -R 94.103.47.66
RSA host key for 94.103.47.66 has changed and you have requested strict checking.
Host key verification failed.
```

Bu noktada SSH kısaca "bağlanmaya çalıştığın sunucunun parmak izi daha önceden farklıydı. Bu şüpheli bir durum. Eğer yine de devam etmek istiyorsan benim kenara not ettiğim satırı sil lütfen" demektedir.

Hata mesajında parmak izini nereye not ettiği görülebilir: `/home/eaydin/.ssh/known_hosts:1` yani bu dosyanın ilk satırı.

Bu satırı silersek, tekrar bize **yes/no** sorusunu soracaktır. Öte yandan tek seferlik bu kontrolü engellemek için aşağıdaki gibi bir bağlantı yapabilirdik.

```bash
eaydin@dixon ~ $ ssh -o UserKnownHostsFile=/dev/null root:@94.103.47.66
The authenticity of host '94.103.47.66 (94.103.47.66)' can't be established.
RSA key fingerprint is c2:54:d7:77:57:76:a1:78:f8:82:8b:48:de:89:71:c5.
Are you sure you want to continue connecting (yes/no)?
```

Aslında yaptığımız `/home/eaydin/.ssh/known_hosts` dosyasını yerine `/dev/null` kullanmak oldu. Bu dosya da boş olunca, yine RSA parmak izini tanıyıp tanımadığımızı sordu. Eğer bu soruyu da sormamasını isteseydik,

```bash
eaydin@dixon ~ $ ssh -o UserKnownHostsFile=/dev/null \
-o StrictHostKeyChecking=no root:@94.103.47.66
Warning: Permanently added '94.103.47.66' (RSA) to the list of known hosts.
root:@94.103.47.66's password:
```

Yukarıdaki mesajda her ne kadar "Permanently added" dese de, eklediği liste dosyası `/dev/null` olduğu için, bu bilgi hiçbir yere kaydedilmemiş oldu.

`known_hosts` dosyasına eklenen bir RSA parmak izini silmek için dosyayı düzenlemek yerine `ssh-keygen` komutunun bir parametresini kullanabilirdik. Bu bizi hashlenmiş dosyada ilgili satırı bulma derdinden kurtarmaktadır. Yukarıdaki örnek için yapacak olursak:

```bash
eaydin@dixon ~ $ ssh-keygen -R 94.103.47.66
# Host 94.103.47.66 found: line 2 type RSA
/home/eaydin/.ssh/known_hosts updated.
Original contents retained as /home/eaydin/.ssh/known_hosts.old
```

## İstemci Ayarları

Yukarıdaki örneklerde `-o` parametresiyle bağlantı sırasında bazı seçenekleri açıp kapattık. Aslında burada yaptığımız, ssh istemcinin tanımlanmış ayarlarında bazılarını kullanmayıp o an belirttiklerimizi zorlamaktı.

SSH istemcisinin davranışını etkileyen ayarlar iki ana dosyada bulunur:

1. **`/etc/ssh/ssh_config`**: Sistem genelindeki varsayılan ayarlar.
2. **`~/.ssh/config`**: Kullanıcıya özel ayarlar. Bu dosyadaki ayarlar, sistem genelindeki ayarları geçersiz kılar (override eder). Sık kullanılan bağlantılar için kısayollar ve özel seçenekler tanımlamak için idealdir.

Örneğin, `/etc/ssh/ssh_config` dosyasında veya `~/.ssh/config` dosyasında `StrictHostKeyChecking no` ayarı yapılırsa, SSH bilinmeyen veya değişmiş anahtarlar için soru sormaz (güvenlik açısından **tavsiye edilmez**). Benzer şekilde, varsayılan kullanıcı, port, kullanılacak kimlik dosyaları (`IdentityFile`), bağlantı zaman aşımı (`ConnectTimeout`) gibi birçok seçenek bu dosyalarda `Host` blokları altında veya genel olarak tanımlanabilir.

Detaylı bilgi için `ssh_config(5)` man sayfasına bakabilirsiniz:

```bash
man 5 ssh_config
```


# sshd Sunucu Ayarları

Bir önceki bölümde istemciyi nasıl kullanacağımızı ve nasıl ayarlayacağımızı gördük. Bu kısımda sunucu üzerinde OpenSSH ayarlamalarını nasıl yapacağımızı göreceğiz.

Genellikle sunucular üzerinde ssh sunucusu yüklü gelir, ancak bazı sistemlerde (örneğin masaüstü sistemlerde) gelmemesi halinde paket yöneticinizden edinebilirsiniz.

Örneğin Ubuntu masaüstü sistemler için aşağıdaki komut ilgili paketleri yükleyecektir.

`apt-get install openssh-server`

## `sshd_config` Dosyası

SSH sunucusunun (sshd - SSH daemon) davranışını kontrol eden ana yapılandırma dosyası genellikle `/etc/ssh/sshd_config` yolunda bulunur. Bu dosyada yapılan değişikliklerin geçerli olması için `sshd` servisinin yeniden yüklenmesi (reload) veya yeniden başlatılması (restart) gerekir.

Buradaki seçenekler istemcide kullanılana benzerdir, ancak bazı noktaların üzerinden geçmekte fayda var.

sshd\_config dosyası hakkında yardım dosyalarına erişmek için

```bash
man 5 sshd_config
```

Aşağıda sıkça değiştirilen veya güvenlik açısından önemli olan bazı seçenekler açıklanmıştır. Dosyadaki varsayılan değerler genellikle `#` ile yorum satırı halindedir; değiştirmek için `#` işaretini kaldırıp istediğiniz değeri yazmalısınız.

### Port

SSH sunucusunun dinleyeceği port numarasını belirtir. Varsayılan değer 22'dir. Güvenlik amacıyla (otomatik saldırıları azaltmak için) bu portu standart olmayan bir porta (örn. 2222) değiştirmek yaygın bir pratiktir.

```
Port 2222 
```

Portu değiştirirseniz, istemciden bağlanırken `-p` seçeneği ile yeni portu belirtmeniz gerekir (`ssh kullanici@sunucu -p 2222`) ve sunucu güvenlik duvarında (firewall) bu porta izin vermelisiniz.

### Protocol

Kullanılacak SSH protokol sürümünü belirtir. SSHv1 güvensizdir ve **kesinlikle kullanılmamalıdır**.

```
Protocol 2
```

Modern sistemlerde bu genellikle varsayılandır veya belirtilmese bile sadece v2 kullanılır.

### Root Girişi (`PermitRootLogin`)

`root` kullanıcısının SSH üzerinden doğrudan bağlanıp bağlanamayacağını kontrol eder. Güvenlik açısından **doğrudan root girişini engellemek şiddetle tavsiye edilir**. Bunun yerine normal bir kullanıcı ile bağlanıp, `sudo` veya `su` komutları ile root yetkisi alınmalıdır.

```
# En güvenli seçenek: Root girişini tamamen engelle
PermitRootLogin no

# Sadece anahtar tabanlı root girişine izin ver, şifre ile girişi engelle
# PermitRootLogin prohibit-password 
# (veya eski sürümlerde: PermitRootLogin without-password)

# Hem şifre hem anahtarla root girişine izin ver (TAVSİYE EDİLMEZ!)
# PermitRootLogin yes 
```

### Şifre ile Kimlik Doğrulama (`PasswordAuthentication`)

Şifre kullanarak SSH bağlantısına izin verilip verilmeyeceğini belirler. Anahtar tabanlı kimlik doğrulama (daha güvenli) kullanılıyorsa, şifre ile kimlik doğrulamayı kapatmak güvenliği artırır.

```
# Şifre ile girişi kapat (Anahtar kullanılmalı)
PasswordAuthentication no

# Şifre ile girişe izin ver (Anahtar yoksa veya tercih edilirse)
# PasswordAuthentication yes 
```

**Not:** Şifre ile girişi kapatmadan önce, en az bir kullanıcı için anahtar tabanlı girişin çalıştığından emin olun, aksi takdirde sunucuya erişiminizi kaybedebilirsiniz!

### Boş Şifre Kullanımı (`PermitEmptyPasswords`)

Boş şifreye sahip kullanıcıların SSH ile bağlanıp bağlanamayacağını belirler. Güvenlik nedeniyle daima `no` olarak ayarlanmalıdır.

```
PermitEmptyPasswords no
```

### Bağlantıyı Canlı Tutma (KeepAlive)

İstemci ile sunucu arasındaki bağlantı belirli süre sonra öldürülebilir. Bunun için sunucunuzda aşağıdaki parametreleri düzenleyebilirsiniz.

```
ClientAliveInterval 300
ClientAliveCountMax 0
```

Yukarıdaki sunucu ayarında istemciden 5 dakikada bir (300 saniye) **alive** sinyali beklenir. Eğer bu sinyali **0** defa göndermezse bağlantı kesilir.

Bu ayarlamaya sahip bir sunucuya bağlanırken ssh istemcinizde

```bash
ssh -o ServerAliveInterval=300 -o ServerAliveCountMax=0 sunucu-adi
```

şeklinde bir kullanıma ihtiyaç duyarsınız. Tabii bu ayarları `/etc/ssh/ssh_config` dosyanıza kaydedebilirsiniz de.

Bir diğer bağlantı canlılığı, şifre sorulduğu anda gerçekleşir. Şifre sorgu ekranının ne kadar süreyle aktif kalacağını `LoginGraceTime` değeriyle düzenleyebilirsiniz.

```
LoginGraceTime 60
```

Yukarıdaki ayar ile kullanıcı 1 dakika içerisinde giriş bilgilerini girmezse sunucudan bağlantısı kesilir. Sonsuza kadar bu süreyi uzatmak için **0** değeri girmek yeterlidir.

### Dosya İzin Kontrolleri (`StrictModes`)

SSH sunucusunun, kullanıcının ev dizini, `.ssh` dizini ve `authorized_keys` dosyası gibi dosyaların izinlerini kontrol edip etmeyeceğini belirler. `yes` olarak ayarlanması (varsayılan), bu dosyaların izinleri güvensizse (örn. başkaları tarafından yazılabilirse) anahtar tabanlı kimlik doğrulamayı reddeder. Güvenlik için `yes` olarak kalması önerilir.

```
StrictModes yes
```

### X11 Forwarding (`X11Forwarding`)

Uzak sunucudaki grafiksel uygulamaların (X11) arayüzünün, güvenli SSH tüneli üzerinden yerel makinenize yönlendirilip yönlendirilmeyeceğini belirler. Güvenlik riskleri oluşturabileceğinden, gerekmiyorsa `no` olarak ayarlanabilir.

```
X11Forwarding yes
```

İstemcide bağlanırken `-X` (güvenilir) veya `-Y` (daha az güvenli ama bazı uygulamalar için gerekli olabilir) parametresi kullanılır.

### Diğer Önemli Ayarlar

* **`PubkeyAuthentication yes`**: Açık anahtar ile kimlik doğrulamayı etkinleştirir (genellikle varsayılan).
* **`AllowUsers` / `AllowGroups`**: Sadece belirtilen kullanıcıların veya grupların SSH ile bağlanmasına izin verir. Güvenliği artırmak için kullanılabilir (örn. `AllowUsers kullanici1 admin`).
* **`DenyUsers` / `DenyGroups`**: Belirtilen kullanıcıların veya grupların SSH ile bağlanmasını engeller.
* **`MaxAuthTries`**: Bir bağlantı için izin verilen maksimum kimlik doğrulama denemesi sayısını sınırlar (örn. `3`). Brute-force saldırılarını yavaşlatır.
* **`UsePAM yes`**: Kimlik doğrulama için PAM (Pluggable Authentication Modules) kullanımını etkinleştirir. Çoğu sistemde varsayılan ve gereklidir (örn. `/etc/pam.d/sshd` yapılandırmasını kullanır).
* **`HostKey`**: Sunucunun kimliğini doğrulamak için kullanacağı özel anahtar dosyalarının yollarını belirtir (örn. `/etc/ssh/ssh_host_ed25519_key`).
* **`HostKeyAlgorithms` / `PubkeyAcceptedKeyTypes` / `KexAlgorithms` / `Ciphers` / `MACs`**: Güvenlik politikalarına göre izin verilen anahtar türlerini, anahtar değişim algoritmalarını, şifreleme algoritmalarını ve mesaj doğrulama kodlarını kısıtlamak için kullanılabilir. Modern ve güvenli algoritmaları (örn. Ed25519, ChaCha20-Poly1305) tercih edip eskileri (örn. DSA, SHA1, CBC) devre dışı bırakmak önerilir.

### Ayarları Uygulama

`/etc/ssh/sshd_config` dosyasında değişiklik yaptıktan sonra, yapılandırmanın geçerli olup olmadığını kontrol etmek ve servisi yeniden yüklemek/başlatmak gerekir:

```bash
# Yapılandırma dosyasının sözdizimini kontrol et
sudo sshd -t

# Eğer hata yoksa, sshd servisini yeniden yükle (genellikle yeterlidir)
sudo systemctl reload sshd
# veya yeniden başlat (gerekirse)
# sudo systemctl restart sshd 
```

Servis adı dağıtıma göre `ssh` veya `sshd` olabilir (`systemctl status sshd` veya `systemctl status ssh` ile kontrol edilebilir).


# Private ve Public Anahtarlar

SSH bağlantılarını şifreler haricinde, anahtarlar ile gerçekleştirebiliriz. Bu sayede sunucuların şifrelerini bilmemiz gerekmez. Başka birilerinin sunucumuza giriş yetkisi edinmesi için erişim şifresini kendileriyle paylaşmak yerine, kendilerinin anahtarlarını sisteme eklememiz yeterli olur.

## Çalışma Biçimi

SSH anahtarları temel olarak şu prensipte çalışır: Anahtarın iki yarısı bulunur. Birisine private (gizli) anahtar, diğerine public (açık) anahtar denilir. Public anahtarı yüklediğiniz sunucular, ilgili private anahtarı elinde bulunduranlara giriş yetkisi verir. Özetle public anahtarınızı herkesle paylaşabilirsiniz, bu yüzden ismi publictir. Ancak sisteminize tanımadığınız public anahtarlar eklememelisiniz, bu durum tanımadığınız kişilere giriş yetkisi vereceğiniz anlamına gelir.

Benzer şekilde private anahtarınızı kimseyle paylaşmamalısınız. Aksi takdirde public anahtarlarınızın yüklü olduğu bütün sistemlere girebilirler.

Oluşturulan private ve public anahtar çiftleri farklı kriptolama teknikleri kullanır.

## Kriptolama Teknikleri ve Anahtar Oluşturma (`ssh-keygen`)

OpenSSH, kimlik doğrulama için çeşitli açık anahtar algoritmalarını destekler. Geçmişte RSA ve DSA yaygın olarak kullanılmış olsa da, günümüzde güvenlik ve performans açısından **Ed25519** algoritması **şiddetle tavsiye edilmektedir**. ECDSA da iyi bir alternatiftir. RSA hala kullanılabilir (özellikle eski sistemlerle uyumluluk için), ancak en az 3072 veya 4096 bit anahtar uzunluğu önerilir. DSA ise artık güvensiz kabul edilmektedir ve kullanılmamalıdır.

SSH anahtar çifti (private ve public) oluşturmak için standart araç `ssh-keygen` programıdır.

**Ed25519 Anahtarı Oluşturma (Önerilen):**

```bash
ssh-keygen -t ed25519 -C "kullanici@makine_adi"
```

* `-t ed25519`: Anahtar türünü Ed25519 olarak belirtir.
* `-C "..."`: Anahtara bir yorum ekler (genellikle e-posta adresi veya kullanıcı@makine formatında). Bu yorum, anahtarı tanımlamaya yardımcı olur ancak işlevsel bir etkisi yoktur.

**RSA Anahtarı Oluşturma (Eski Sistemlerle Uyumlu):**

```bash
ssh-keygen -t rsa -b 4096 -C "kullanici@makine_adi"
```

* `-t rsa`: Anahtar türünü RSA olarak belirtir.
* `-b 4096`: Anahtar uzunluğunu bit cinsinden belirtir (RSA için en az 3072 veya 4096 önerilir).

`ssh-keygen` komutu çalıştırıldığında size birkaç soru soracaktır:

1. **Dosya Yolu:** Anahtarın nereye kaydedileceğini sorar. Varsayılan yol genellikle kullanıcının ev dizinindeki `~/.ssh/` klasörüdür (örn. `~/.ssh/id_ed25519` veya `~/.ssh/id_rsa`). Varsayılanı kabul etmek için Enter'a basabilir veya farklı bir yol/isim belirtebilirsiniz.
2. **Parola (Passphrase):** Özel anahtarınızı korumak için bir parola belirlemenizi ister. **Güçlü bir parola belirlemek şiddetle tavsiye edilir.** Bu parola, özel anahtarınızın çalınması durumunda bile kullanılmasını engeller. Parola olmadan anahtar oluşturmak için bu adımı boş geçebilirsiniz (Enter'a iki kez basın), ancak bu daha az güvenlidir.

Örnek Ed25519 anahtar oluşturma adımları:

```bash
$ ssh-keygen -t ed25519 -C "test@example.com"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:aBcDeFgHiJkLmNoPqRsTuVwXyZ1234567890abcDef user@hostname
The key's randomart image is:
+--[ED25519 256]--+
|        . .. .   |
|       . + ..    |
|      . =.o ..   |
|     . *.*o..    |
|    . = S=o.     |
|   . =.B.B .     |
|    =o*.B . .    |
|   =o=o= . .     |
|  .E+*+..        |
+----[SHA256]-----+
```

Anahtar çifti oluşturmak istediğimiz belirttikten sonra program bize dosyayı nereye kaydedeceğini sorar, standart yolu kullanıcının ev dizininin altındaki `.ssh` dizini'dir.

Anahtar çiftinin yolunu belirttikten sonra, anahtarımızı şifrelemek istiyorsak bize şifresini sorar. Bu adımı boş bırakırsak anahtarımız şifresiz kullanılabilir olur. Bir şifre belirlemenizi şiddetle tavsiye ediyoruz. Böylece özel anahtarınız başkası tarafından çalınsa bile, şifreyi bilmedikleri için kullanamayacaklardır.

Örnek adımlar aşağıdaki gibi görülebilir.

```bash
eaydin@dixon ~/calisma/anahtar $ ssh-keygen -t rsa -b 4096 -C "egitim@veriteknik.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/eaydin/.ssh/id_rsa): egitim_rsa
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in egitim_rsa.
Your public key has been saved in egitim_rsa.pub.
The key fingerprint is:
41:67:e7:38:b4:9e:fe:94:c8:47:73:be:77:77:d6:ce egitim@veriteknik.com
The key's randomart image is:
+--[ RSA 4096]----+
|        . + .    |
|       . + =     |
|        . + .    |
|         o o     |
|        S o o .  |
|         o o =   |
|          + + . .|
|           +   oB|
|            . .+E|
+-----------------+
```

Bu işlemlerin ardından iki dosya oluşur:

* `id_ed25519` (veya belirttiğiniz isim): **Özel (Private) Anahtar**. Bu dosyayı **gizli tutmalı** ve kimseyle paylaşmamalısınız. İzinleri genellikle `600` (`-rw-------`) olmalıdır.
* `id_ed25519.pub` (veya belirttiğiniz isim`.pub`): **Açık (Public) Anahtar**. Bu dosyanın içeriğini, şifresiz bağlanmak istediğiniz uzak sunuculardaki ilgili kullanıcının `~/.ssh/authorized_keys` dosyasına eklemelisiniz. Bu anahtarı başkalarıyla paylaşmanızda genellikle bir sakınca yoktur.

### `authorized_keys` Dosyası ve İzinler

Uzak sunucuda, bağlanmak istediğiniz kullanıcının ev dizini altında `~/.ssh/authorized_keys` dosyası bulunur. Bu dosya, o kullanıcı olarak sunucuya bağlanmasına izin verilen kişilerin **açık (public)** anahtarlarını içerir (her anahtar genellikle tek bir satırda yer alır).

Yerel makinenizde oluşturduğunuz `.pub` uzantılı dosyanın içeriğini kopyalayıp, uzak sunucudaki ilgili kullanıcının `~/.ssh/authorized_keys` dosyasının sonuna eklemeniz gerekir.

**Önemli Dosya İzinleri:** SSH anahtar tabanlı kimlik doğrulamanın çalışması için uzak sunucudaki dosya ve dizin izinleri çok önemlidir:

* Kullanıcının ev dizini (`~`) grup veya diğer kullanıcılar tarafından yazılabilir olmamalıdır (`drwxr-xr-x` veya `755` genellikle uygundur).
* `.ssh` dizininin izinleri `700` (`drwx------`) olmalıdır (sadece sahip okuyabilir, yazabilir, çalıştırabilir).
* `authorized_keys` dosyasının izinleri `600` (`-rw-------`) olmalıdır (sadece sahip okuyabilir, yazabilir).

Bu izinler doğru ayarlanmazsa, SSH sunucusu güvenlik nedeniyle anahtar tabanlı kimlik doğrulamayı reddedebilir.

### Açık Anahtarı Sunucuya Kopyalama (`ssh-copy-id`)

Açık anahtarınızı (`.pub` dosyasının içeriğini) manuel olarak kopyalayıp `authorized_keys` dosyasına eklemek yerine, `ssh-copy-id` komutunu kullanmak daha kolay ve genellikle daha güvenli bir yoldur. Bu komut, belirtilen sunucuya şifre ile bağlanır (eğer şifre tabanlı giriş açıksa) ve yerel makinenizdeki açık anahtarı otomatik olarak uzak sunucudaki doğru `authorized_keys` dosyasına ekler, ayrıca gerekli dizin ve dosya izinlerini de ayarlamaya çalışır.

```bash
# Varsayılan anahtarı (örn. ~/.ssh/id_ed25519.pub) kopyala
ssh-copy-id kullanici@uzak_sunucu_adresi

# Belirli bir anahtarı (-i) ve portu (-p) kullanarak kopyala
ssh-copy-id -i ~/.ssh/baska_bir_anahtar.pub -p 2299 kullanici@uzak_sunucu_adresi
```

Komut sizden uzak sunucudaki kullanıcının şifresini isteyecektir. Başarıyla tamamlandıktan sonra, artık o sunucuya şifre yerine SSH anahtarınızla (ve eğer belirlediyseniz anahtar parolanızla) bağlanabilirsiniz.

```bash
eaydin@dixon ~ $ ssh-copy-id root@test-centos1
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
Host key fingerprint is 9c:74:68:d4:2d:93:70:bb:fe:c1:e7:6e:63:b0:f0:f1
root@test-centos1's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'root@test-centos1'"
and check to make sure that only the key(s) you wanted were added.
```

`ssh-copy-id` komutu, anahtar zaten `authorized_keys` dosyasında varsa tekrar eklemez. `-n` seçeneği ile kopyalama işlemini yapmadan sadece deneme (dry-run) yapabilirsiniz.


# Güvenli Dosya Aktarımı

SSH protokolünü kullanarak güvenli dosya transferi sağlamak mümkündür. Bunun için scp, sftp veya rsync kullanılabilir.

## rsync

`rsync` (remote sync), dosyaları ve dizinleri yerel olarak veya uzak sistemler arasında verimli bir şekilde senkronize etmek için kullanılan çok güçlü bir araçtır. Sadece değişen dosya bölümlerini transfer eden delta transfer algoritması sayesinde özellikle yedekleme ve büyük veri transferleri için çok popülerdir.

`rsync`, varsayılan olarak SSH protokolünü kullanarak güvenli bir bağlantı kurar, ancak kendi `rsync` daemon protokolü üzerinden veya yerel dosya sistemleri arasında da çalışabilir. Kullanımı oldukça esnektir.

**Temel Kullanım (SSH üzerinden):**

* **Yerelden Uzak Sunucuya:**

  ```bash
  # /yerel/dizin içeriğini uzak sunucudaki /uzak/dizin içine kopyala/eşitle
  # -a: arşiv modu (izinleri, zamanları, sembolik linkleri vb. korur, -rlptgoD ile eşdeğer)
  # -v: verbose (detaylı çıktı)
  # -z: transfer sırasında sıkıştırma uygula
  rsync -avz /yerel/dizin/ root@UZAK_SUNUCU:/uzak/dizin/ 
  ```

  **Not:** Kaynak dizinin sonundaki `/` işareti önemlidir. `/yerel/dizin/` kullanıldığında dizinin *içeriği* hedefe kopyalanır. `/yerel/dizin` kullanıldığında ise dizinin *kendisi* (ve içeriği) hedefin içine kopyalanır (yani `/uzak/dizin/dizin` oluşur).
* **Uzak Sunucudan Yerele:**

  ```bash
  rsync -avz root@UZAK_SUNUCU:/uzak/dizin/ /yerel/dizin/
  ```
* **SSH Portu Belirtme:**

  ```bash
  rsync -avz -e 'ssh -p 2222' /yerel/dizin/ root@UZAK_SUNUCU:/uzak/dizin/
  ```
* **Simülasyon (Dry Run):** `-n` veya `--dry-run` seçeneği ile hangi dosyaların transfer edileceğini görebilir, ancak gerçek transferi yapmazsınız.

  ```bash
  rsync -avzn /yerel/dizin/ root@UZAK_SUNUCU:/uzak/dizin/
  ```
* **Hedefte Olmayan Dosyaları Silme:** `--delete` seçeneği, kaynakta bulunmayan dosyaların hedef dizinden silinmesini sağlar (dikkatli kullanılmalıdır!).

  ```bash
  rsync -avz --delete /yerel/dizin/ root@UZAK_SUNUCU:/uzak/dizin/
  ```

rsync, argüman sayısının fazlalığından dolayı (1 milyon ve üzeri) "rm" komutunun dahi silemediği dosyaları kolaylıkla siler. Bu dosyaları silmek için hedefteki dizini boş bir dizin ile eşleştirmeniz yeterlidir.

## scp (Secure Copy)

`scp`, SSH protokolünü kullanarak dosyaları yerel ve uzak sistemler arasında güvenli bir şekilde kopyalamak için kullanılan klasik bir komuttur. Kullanımı `cp` komutuna benzer.

Uzak sunucudan dosya indirmek için

```bash
scp root@192.168.168.5:/root/dosya.tar.gz /home/eaydin
```

Uzak sunucuya dosya göndermek için

```bash
scp /root/dosya.tar test@10.42.30.65:/opt/settings
```

Eğer sunucunun SSH portu 22'den farklıysa, `-P` parametresiyle bağlantı portunu tanımlayabilirsiniz.

```bash
scp -P 2299 root@192.168.1.30:/var/log/syslog .
```

### İki Uzak Sunucu Arasında Kopyalama Yapmak

Örneğin Veriteknik Sunucu Merkezinde iki sunucumuz var ve bu sunucular arasında scp ile dosya transferi gerçekleştirmek istiyoruz. Bunun için sunuculardan birine SSH ile bağlanıp, onun üzerinden diğerine scp ile dosya transferi başlatabiliriz.

Ancak alternatif bir yöntem, scp'nin **-3** parametresini kullanmak.

```bash
scp -3 root@sunucu1:/var/log/syslog root@sunucu2:/root/backups
```

Yukarıdaki yöntem ile dosyalar doğrudan transfer edilecektir. Ancak bunun için OpenSSH versiyonunun 5.7+ olması gerekmektedir.

**Not:** Modern OpenSSH sürümlerinde `scp` komutu, arka planda genellikle SFTP protokolünü kullanır. Bu, eski `scp` protokolünün bazı sınırlamalarını (örn. hata bildirme) ortadan kaldırır. Ancak `scp` komutunun sözdizimi ve temel işlevi aynı kalmıştır.

## sftp (SSH File Transfer Protocol)

`sftp`, SSH üzerinden güvenli dosya transferi yapmak için tasarlanmış ayrı bir protokoldür ve genellikle `scp`'ye göre daha fazla özellik sunan interaktif bir komut satırı istemcisi (`sftp`) ile birlikte gelir. FTP komutlarına benzer bir arayüz sunar.

**Avantajları:**

* İnteraktif oturum: Bağlantı kurulduktan sonra `ls`, `cd`, `get`, `put`, `mkdir`, `rm` gibi komutlarla uzak dosya sistemi üzerinde gezinebilir ve işlem yapabilirsiniz.
* Dosya listeleme, dizin oluşturma/silme, yeniden adlandırma gibi dosya sistemi işlemleri yapabilme.
* Yarım kalan transferleri devam ettirme (`reget`, `reput` - sunucu ve istemci desteğine bağlı).

**Dezavantajları:**

* `scp`'ye göre bazı durumlarda biraz daha yavaş olabilir (protokol ek yükü nedeniyle).
* Basit tek dosya transferleri için `scp` kadar hızlı olmayabilir.

Bir sunucuya SFTP bağlantısı kurmak için aşağıdaki gibi bir yol izlenir.

```bash
eaydin@dixon ~ $ sftp root@test-centos1
Connected to test-centos1.
sftp>
```

Artık karşı sunucuya SFTP ile bağlanmış olursunuz. Kullanabileceğiniz komutları görmek için **?** yazılıp ENTER'a basılabilir.

```bash
sftp> ?
Available commands:
bye                                Quit sftp
cd path                            Change remote directory to 'path'
chgrp grp path                     Change group of file 'path' to 'grp'
chmod mode path                    Change permissions of file 'path' to 'mode'
chown own path                     Change owner of file 'path' to 'own'
df [-hi] [path]                    Display statistics for current directory or
                                   filesystem containing 'path'
exit                               Quit sftp
get [-Ppr] remote [local]          Download file
reget remote [local]        Resume download file
help                               Display this help text
lcd path                           Change local directory to 'path'
lls [ls-options [path]]            Display local directory listing
lmkdir path                        Create local directory
ln [-s] oldpath newpath            Link remote file (-s for symlink)
lpwd                               Print local working directory
ls [-1afhlnrSt] [path]             Display remote directory listing
lumask umask                       Set local umask to 'umask'
mkdir path                         Create remote directory
progress                           Toggle display of progress meter
put [-Ppr] local [remote]          Upload file
pwd                                Display remote working directory
quit                               Quit sftp
rename oldpath newpath             Rename remote file
rm path                            Delete remote file
rmdir path                         Remove remote directory
symlink oldpath newpath            Symlink remote file
version                            Show SFTP version
!command                           Execute 'command' in local shell
!                                  Escape to local shell
?                                  Synonym for help
```

Burada bilinmesi gereken önemli noktalar şunlardır:

* Mevcut sistemimizde (örneğin kullandığımız laptop) bir komut çalıştırmak istersek, komutun başına **!** koyabiliriz.

```bash
sftp> lsblk
Invalid command.
sftp> !lsblk
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda      8:0    0 931,5G  0 disk 
├─sda1   8:1    0   350M  0 part 
├─sda2   8:2    0   200G  0 part 
├─sda3   8:3    0 350,9G  0 part /
├─sda4   8:4    0     1K  0 part 
├─sda5   8:5    0   6,9G  0 part [SWAP]
└─sda6   8:6    0 373,5G  0 part /media/backups
sr0     11:0    1  1024M  0 rom
```

* Ayrıca mevcut sistemde bazı yerel komutlar çalıştırmak için komutun başına **l** harfi (**l**ocal) konulur. Örneğin `!cd` çalışmayacağı için, `lcd` kullanılır.
* Dosya indirmek (download) için `get` komutu kullanılır. `mget` (multiple get) genellikle joker karakterlerle birden fazla dosya indirmek için kullanılır (bazı istemcilerde desteklenmeyebilir). Yarım kalan dosya indirme işlemlerini devam ettirmek için `reget` kullanılır.
* Dosya yüklemek (upload) için `put` komutu kullanılır. `mput` (multiple put) benzer şekilde birden fazla dosya yüklemek için kullanılır. Yarım kalan yüklemeleri devam ettirmek için `reput` kullanılır.


# sshfs

**sshfs** (SSH File System), FUSE (Filesystem in Userspace) kullanarak uzak bir sunucudaki bir dizini yerel makinenizdeki bir dizin gibi bağlamanıza (mount) olanak tanıyan bir araçtır. Tüm dosya transferi SSH protokolü üzerinden güvenli bir şekilde yapılır. Bu sayede uzak dosyalara yerel uygulamalarınızla (dosya yöneticisi, metin düzenleyici vb.) doğrudan erişebilirsiniz.

**Kurulum:**`sshfs` genellikle sistemlerde önyüklü gelmez. Paket yöneticinizle kurmanız gerekir:

```bash
# Debian/Ubuntu
sudo apt install sshfs

# RHEL/CentOS/Fedora
sudo dnf install fuse-sshfs 

# Arch Linux
sudo pacman -S sshfs
```

Ayrıca, kullanıcınızın FUSE dosya sistemlerini bağlayabilmesi için genellikle `fuse` grubuna üye olması gerekebilir (`sudo usermod -aG fuse $USER` komutu sonrası yeniden giriş yapmanız gerekebilir) veya `/etc/fuse.conf` dosyasında `user_allow_other` seçeneğinin aktif edilmesi gerekebilir.

## Uzak Dosya Sistemini Bağlama (Mount)

1. **Yerel Bağlama Noktası Oluşturma:** Uzak dizini bağlamak için yerel sisteminizde boş bir dizin oluşturun:

   ```bash
   mkdir ~/uzak-sunucu
   ```
2. **`sshfs` Komutu ile Bağlama:**

   ```bash
   # Temel kullanım: sshfs [kullanici@]sunucu:[uzak_dizin] /yerel/baglama/noktasi
   sshfs root@sunucu-ip:/remote/dizin ~/uzak-sunucu 
   ```

   * `root@sunucu-ip`: Uzak sunucudaki kullanıcı adı ve sunucu adresi/IP'si.
   * `:/remote/dizin`: Uzak sunucuda bağlanılacak dizin (boş bırakılırsa kullanıcının ev dizini).
   * `~/uzak-sunucu`: Yerel makinede oluşturulan bağlama noktası.

   **Seçenekler:**

   * **Port Belirtme:** `-p` seçeneği yerine `-o port=PORT_NO` kullanılır:

     ```bash
     sshfs root@sunucu-ip:/remote/dizin ~/uzak-sunucu -o port=2222
     ```
   * **Anahtar Kullanma:** `-o IdentityFile=ANAHTAR_YOLU` kullanılır:

     ```bash
     sshfs root@sunucu-ip:/remote/dizin ~/uzak-sunucu -o IdentityFile=~/.ssh/id_ed25519
     ```
   * **Diğer Kullanıcıların Erişimi:** Varsayılan olarak sadece bağlayan kullanıcı erişebilir. Diğer kullanıcıların da erişmesi için `allow_other` seçeneği kullanılır (genellikle `/etc/fuse.conf` içinde `user_allow_other` ayarı da gerekir):

     ```bash
     sshfs root@sunucu-ip:/remote/dizin ~/uzak-sunucu -o allow_other
     ```
   * **Bağlantı Kopmalarına Karşı:** Bağlantı koptuğunda otomatik yeniden bağlanmayı denemek için:

     ```bash
     sshfs root@sunucu-ip:/remote/dizin ~/uzak-sunucu -o reconnect
     ```

   Artık `~/uzak-sunucu` dizini altında yapacağınız dosya işlemleri (listeleme, okuma, yazma vb.) SSH üzerinden uzak sunucuda gerçekleşecektir.

## Otomatik Bağlama (`/etc/fstab`)

`sshfs` bağlantısının sistem başlangıcında otomatik olarak yapılmasını sağlamak için `/etc/fstab` dosyasına bir satır eklenebilir. Ancak bu yöntem, ağ bağlantısı hazır olmadan veya uzak sunucuya ulaşılamadığında sistem başlangıcının yavaşlamasına veya takılmasına neden olabilir. **Dikkatli kullanılmalıdır.**

Örnek `/etc/fstab` satırı:

```
# Kullanıcı 'kullanici_adi' olarak bağlanacak, anahtar kullanılacak, ağ beklenilecek
kullanici_adi@sunucu-ip:/uzak/dizin  /yerel/baglama/noktasi  fuse.sshfs  defaults,_netdev,user,identityfile=/home/kullanici_adi/.ssh/id_ed25519,allow_other,reconnect  0  0
```

* `kullanici_adi@sunucu-ip:/uzak/dizin`: Uzak kaynak.
* `/yerel/baglama/noktasi`: Yerel bağlama noktası.
* `fuse.sshfs`: Dosya sistemi türü.
* `defaults`: Standart bağlama seçenekleri.
* `_netdev`: Bu bir ağ aygıtıdır, ağ hazır olana kadar bağlama işlemini geciktirir.
* `user`: Normal kullanıcıların bağlamasına/ayırmasına izin verir (genellikle `allow_other` ile birlikte kullanılırsa anlamlıdır veya bağlama noktasının sahibi ilgili kullanıcı olmalıdır).
* `identityfile=...`: Kullanılacak özel anahtar dosyasının tam yolu.
* `allow_other`: Diğer kullanıcıların da erişimine izin verir (güvenlik etkilerini göz önünde bulundurun).
* `reconnect`: Bağlantı koparsa yeniden bağlanmayı dener.
* `0 0`: Dump ve fsck kontrolü için (ağ dosya sistemleri için genellikle 0).

**Alternatifler:** `/etc/fstab` yerine `systemd mount` veya `autofs` gibi daha modern ve esnek otomatik bağlama yöntemleri de kullanılabilir.

## Bağlantıyı Kesme (Unmount)

Bağlı uzak dosya sistemini ayırmak için standart `umount` komutu kullanılır:

```bash
umount ~/uzak-sunucu
```

Eğer "device is busy" hatası alırsanız, bağlama noktası içinde çalışan bir işlem olmadığından emin olun veya `-l` (lazy unmount) seçeneğini deneyin: `umount -l ~/uzak-sunucu`.


# Kernel Boot

Bu bölüm, bir Linux sisteminin açılış (boot) sürecinin temel adımlarını ele almaktadır. Bilgisayarın güç düğmesine basıldığı andan itibaren işletim sistemi çekirdeğinin (kernel) yüklenmesi ve ilk kullanıcı alanı (user space) işlemlerinin başlamasına kadar geçen süreç incelenecektir.

İncelenecek konular şunlardır:

* [Sunucu Başlangıcına Genel Bakış](/kernel-boot/sunucu-baslangicina-genel-bakis): BIOS/UEFI, MBR/GPT ve bootloader arasındaki ilişki.
* [Bootloader Nedir?](/kernel-boot/bootloader-nedir): GRUB gibi önyükleyicilerin görevleri.
* [Çekirdeğin Yüklenmesi ve Boot Seçenekleri](/kernel-boot/cekirdegin-yueklenmesi-ve-boot-secenekleri): Çekirdek imajı, initramfs/initrd ve önyükleyici menüsü.
* [Çekirdek Parametreleri](/kernel-boot/cekirdek-parametreleri): Çekirdeğin davranışını değiştirmek için kullanılan parametreler.

Bu bölüm, sistemin nasıl başladığını anlamak ve olası açılış sorunlarını gidermek için temel bilgiler sunar.


# Sunucu Başlangıcına Genel Bakış

Bir Linux sunucusunun (veya herhangi bir modern bilgisayarın) açılış (boot) süreci, güç düğmesine basıldığı andan itibaren kullanıma hazır hale gelene kadar bir dizi adımdan oluşur. Bu adımlar genel olarak aşağıdaki sırayı takip eder:

1. **Güç Verilmesi ve Donanım Başlatma:**
   * Güç düğmesine basıldığında, güç kaynağı (PSU) sisteme enerji sağlar.
   * Anakart üzerindeki temel donanımlar (CPU, RAM vb.) başlatılır.
2. **Firmware (BIOS veya UEFI):**
   * İşlemci, anakart üzerinde bulunan firmware yazılımını çalıştırmaya başlar. Bu yazılım ya eski **BIOS** (Basic Input/Output System) ya da modern **UEFI** (Unified Extensible Firmware Interface) olabilir.
   * **POST (Power-On Self-Test):** Firmware, temel donanımların (RAM, CPU, klavye vb.) çalışıp çalışmadığını kontrol eden bir dizi test gerçekleştirir.
   * **Donanım Algılama ve Başlatma:** Depolama aygıtları (diskler), ağ kartları gibi diğer donanımlar algılanır ve temel düzeyde başlatılır.
   * **Önyükleyici (Bootloader) Arama ve Yükleme:** Firmware, yapılandırılmış önyükleme sırasına göre (boot order) önyüklenebilir bir aygıt arar.
     * **BIOS/MBR:** Geleneksel BIOS sistemleri, genellikle diskin ilk sektöründe bulunan **MBR**'ı (Master Boot Record) okur. MBR, küçük bir önyükleyici kodu (ilk aşama önyükleyici) ve disk bölüm tablosunu içerir. Bu ilk aşama kod, genellikle daha büyük olan ikinci aşama önyükleyiciyi (örn. GRUB'ın bir kısmını) diskteki başka bir yerden yükler.
     * **UEFI/GPT:** Modern UEFI sistemleri, genellikle **GPT** (GUID Partition Table) ile bölümlenmiş diskleri kullanır. UEFI, disk üzerinde özel olarak biçimlendirilmiş (FAT32) bir **EFI Sistem Bölümü** (EFI System Partition - ESP) arar. Bu bölümde bulunan önyükleyici uygulamalarını (`.efi` dosyaları, örn. GRUB veya systemd-boot için) doğrudan çalıştırır. UEFI, MBR'a göre daha esnek ve güvenli bir önyükleme süreci sunar.
3. **Önyükleyici (Bootloader - Örn. GRUB, systemd-boot):**
   * Firmware tarafından yüklenen önyükleyici (genellikle GRUB - GRand Unified Bootloader veya systemd-boot) kontrolü devralır.
   * **Çekirdek (Kernel) ve Initramfs'i Yükleme:** Önyükleyici, yapılandırma dosyasına göre (örn. `/boot/grub/grub.cfg`) seçilen Linux çekirdek imajını (`vmlinuz-...`) ve başlangıç RAM dosya sistemini (**initramfs** veya eski sistemlerde **initrd**) belleğe yükler.
   * **Önyükleme Menüsü:** Genellikle kullanıcıya farklı çekirdek sürümlerini veya işletim sistemlerini seçme, çekirdek parametrelerini düzenleme imkanı sunan bir menü gösterir.
   * **Kontrolü Çekirdeğe Devretme:** Seçilen çekirdeği bellekte çalıştırır ve ona gerekli bilgileri (çekirdek parametreleri, initramfs'in konumu vb.) iletir.
4. **Çekirdek (Kernel) Başlatma:**
   * Çekirdek kontrolü devralır ve kendini bellekte açar (decompress).
   * **Donanım Başlatma:** CPU, bellek yönetimi gibi temel sistemleri kurar ve algılanan donanımlar için gerekli sürücüleri (genellikle initramfs içindekileri kullanarak) yüklemeye başlar.
   * **Initramfs:** Belleğe yüklenen initramfs (initial RAM filesystem), kök dosya sisteminin bağlanabilmesi için gerekli sürücüleri (disk, dosya sistemi, LVM, RAID vb.) içeren geçici bir kök dosya sistemidir. Çekirdek, initramfs içindeki bir başlangıç betiğini çalıştırır.
   * **Kök Dosya Sistemini Bağlama (Mount):** Initramfs içindeki betikler, gerçek kök dosya sistemini (`/`) bulur ve genellikle salt okunur (read-only) olarak bağlar.
   * **Init Sürecini Başlatma:** Çekirdek, kök dosya sistemi üzerindeki `/sbin/init` programını (veya çekirdek parametresi ile belirtilmişse farklı bir programı) **PID 1** olarak çalıştırır ve kontrolü ona devreder.
5. **Init Süreci (PID 1 - Örn. systemd, SysV init):**
   * `init` (veya modern sistemlerde genellikle `systemd`), kullanıcı alanındaki (user space) ilk işlemdir ve diğer tüm sistem işlemlerinin atasıdır.
   * **Sistemi Başlatma:** Yapılandırma dosyalarına göre (örn. systemd için unit dosyaları, SysV init için runlevel betikleri) gerekli servisleri (ağ, depolama, günlükleme, kullanıcı girişi vb.) başlatır.
   * **Hedef Duruma Ulaşma:** Sistemi, tanımlanan hedef duruma (target veya runlevel) getirir (örn. çok kullanıcılı komut satırı veya grafiksel arayüz).

Bu adımların sonunda sistem kullanıma hazır hale gelir ve kullanıcı giriş yapabilir. Her adım, bir sonrakinin çalışması için gerekli ortamı hazırlar.


# Çekirdeğin Yüklenmesi ve Boot Seçenekleri

Önyükleyici (bootloader), firmware'den kontrolü aldıktan sonraki ana görevi, işletim sistemi çekirdeğini (kernel) ve başlangıç için gerekli olan başlangıç RAM dosya sistemini (initramfs) belleğe yüklemektir.

## Çekirdek İmajı (Kernel Image)

* **Konum:** Linux çekirdeği, genellikle `/boot` dizini altında sıkıştırılmış bir dosya olarak bulunur. Dosya adı dağıtıma ve sürüme göre değişir, ancak yaygın isimler `vmlinuz-<sürüm>` veya `bzImage-<sürüm>` şeklindedir (örn. `/boot/vmlinuz-6.1.0-18-amd64`).
* **İşlevi:** Çekirdek, işletim sisteminin kalbidir. Donanımı yönetir, işlemleri zamanlar, belleği yönetir ve sistem çağrıları aracılığıyla kullanıcı alanı (user space) programlarına hizmet verir. Önyükleyici tarafından belleğe yüklenir ve çalıştırılır.

## Başlangıç RAM Dosya Sistemi (initrd / initramfs)

* **Konum:** Çekirdek imajı gibi, genellikle `/boot` dizini altında bulunur. Dosya adı `initrd.img-<sürüm>` veya `initramfs-<sürüm>.img` gibi olabilir (örn. `/boot/initramfs-6.1.0-18-amd64.img`).
* **İşlevi:** Çekirdek başlatıldıktan hemen sonra, ancak gerçek kök dosya sistemi (`/`) bağlanmadan önce, bellekte (RAM) geçici bir kök dosya sistemi olarak kullanılır. Temel amacı, gerçek kök dosya sistemini bağlamak için gerekli olan modülleri ve araçları içermektir. Bunlar şunları içerebilir:
  * Disk denetleyici sürücüleri (SATA, NVMe, SCSI vb.).
  * Dosya sistemi sürücüleri (ext4, xfs, btrfs vb.).
  * Mantıksal Birim Yönetimi (LVM) veya yazılımsal RAID araçları ve modülleri.
  * Şifreli diskleri açmak için gerekli araçlar (cryptsetup).
  * Ağ sürücüleri (ağ üzerinden boot yapılıyorsa).
* **Oluşturulması:** Initramfs, genellikle çekirdek kurulduğunda veya güncellendiğinde otomatik olarak sisteme özgü olarak oluşturulur. Bu işlemi yapan araçlar dağıtıma göre değişir:
  * `mkinitrd` (Eski RHEL/CentOS)
  * `dracut` (Modern RHEL/CentOS/Fedora)
  * `mkinitcpio` (Arch Linux)
  * `update-initramfs` (Debian/Ubuntu)
* **initrd vs initramfs:** `initrd` (initial RAM disk) daha eski bir yöntemdi ve sıkıştırılmış bir dosya sistemi imajı (örn. ext2) olarak yüklenirdi. `initramfs` (initial RAM filesystem) ise daha modern bir yöntemdir ve sıkıştırılmış bir `cpio` arşivi olarak yüklenir. Daha esnektir ve genellikle daha az bellek kullanır. Günümüzdeki çoğu sistem `initramfs` kullanır.

## Önyükleyici Yapılandırması ve Menüsü

Önyükleyici (örn. GRUB, systemd-boot), hangi çekirdek ve initramfs dosyasını yükleyeceğini, hangi çekirdek parametrelerini geçeceğini yapılandırma dosyasından okur.

* **GRUB 2:** Ana yapılandırma `/boot/grub/grub.cfg` dosyasındadır. Bu dosya genellikle `update-grub` veya `grub-mkconfig -o /boot/grub/grub.cfg` komutları tarafından `/etc/default/grub` ve `/etc/grub.d/` altındaki betikler kullanılarak otomatik olarak oluşturulur.
* **systemd-boot:** Yapılandırma EFI Sistem Bölümü (ESP) içindedir. `/boot/loader/loader.conf` genel ayarları, `/boot/loader/entries/` altındaki `.conf` dosyaları ise her bir önyükleme girdisini (çekirdek, initramfs, parametreler) tanımlar.

Sistem açılırken, önyükleyici genellikle bir menü gösterir. Bu menü şunları sağlar:

* Farklı işletim sistemleri veya çekirdek sürümleri arasında seçim yapma.
* Belirli bir önyükleme girdisi için çekirdek parametrelerini geçici olarak düzenleme (örn. tek kullanıcı moduna geçmek için `single` veya `init=/bin/bash` eklemek).
* Belirli bir süre (timeout) sonunda varsayılan girdiyi otomatik olarak başlatma.

## Yükleme Süreci

1. Önyükleyici, yapılandırmasına göre seçilen (veya varsayılan) çekirdek imajını ve ilgili initramfs dosyasını diskten okuyarak belleğe (RAM) yükler.
2. Önyükleyici, yapılandırmada tanımlanan veya menüden eklenen çekirdek parametrelerini hazırlar.
3. Önyükleyici, kontrolü belleğe yüklediği çekirdeğin başlangıç noktasına devreder ve çekirdek parametrelerini iletir.
4. Çekirdek çalışmaya başlar, initramfs'i bağlar ve init sürecini başlatmak için gerekli adımları atar.


# Çekirdek Parametreleri

Çekirdek parametreleri (kernel command-line parameters), önyükleyici (bootloader) tarafından Linux çekirdeğine, açılış sırasında davranışını değiştirmek veya donanım hakkında bilgi vermek amacıyla iletilen metin tabanlı seçeneklerdir. Bu parametreler, çekirdeğin donanımı nasıl algılayacağından, kök dosya sisteminin nerede bulunacağına ve sistemin hangi başlangıç modunda açılacağına kadar birçok şeyi etkileyebilir.

## Parametreler Nasıl İletilir?

Çekirdek parametreleri, önyükleyici (GRUB, systemd-boot vb.) tarafından çekirdek belleğe yüklendikten hemen sonra, çekirdek çalıştırılmadan önce ona iletilir.

* **Geçici Olarak Düzenleme:** Çoğu önyükleyici, açılış sırasında bir menü sunar. Bu menüde genellikle belirli bir önyükleme girdisini düzenleme seçeneği bulunur (GRUB'da genellikle 'e' tuşu). Bu sayede, sadece o anki açılış için geçerli olacak şekilde parametreleri ekleyebilir, silebilir veya değiştirebilirsiniz. Bu, sorun giderme veya test amaçlı çok kullanışlıdır.
* **Kalıcı Olarak Düzenleme:** Parametreleri her açılışta geçerli olacak şekilde ayarlamak için önyükleyicinin yapılandırma dosyasını düzenlemek gerekir:
  * **GRUB 2:** `/etc/default/grub` dosyasındaki `GRUB_CMDLINE_LINUX` veya `GRUB_CMDLINE_LINUX_DEFAULT` satırları düzenlenir. Değişiklik sonrası, yeni yapılandırmanın ana GRUB dosyasına (`/boot/grub/grub.cfg`) yazılması için `sudo update-grub` (Debian/Ubuntu) veya `sudo grub-mkconfig -o /boot/grub/grub.cfg` (Fedora/RHEL/Arch vb.) komutu çalıştırılmalıdır.
  * **systemd-boot:** EFI Sistem Bölümü (ESP) içindeki `/boot/loader/entries/` dizinindeki ilgili `.conf` dosyasındaki `options` satırı düzenlenir.

## Mevcut Parametreleri Görme

Sistem çalışırken, o anki açılışta çekirdeğe hangi parametrelerin iletildiğini görmek için `/proc/cmdline` dosyası okunabilir:

```bash
cat /proc/cmdline
```

Örnek Çıktı:

```
BOOT_IMAGE=/boot/vmlinuz-6.1.0-18-amd64 root=UUID=xxxx-xxxx ro quiet splash
```

## Yaygın Çekirdek Parametreleri

Aşağıda sıkça kullanılan bazı çekirdek parametreleri ve açıklamaları verilmiştir:

* **`root=`**: Kök dosya sisteminin (`/`) bulunduğu aygıtı belirtir. Farklı formatlarda belirtilebilir:
  * Aygıt adı: `root=/dev/sda2` (Disk sırası değişebileceği için daha az güvenilir)
  * UUID: `root=UUID=abcdef12-3456-7890-abcd-ef1234567890` (En güvenilir yöntem)
  * LABEL: `root=LABEL=ArchRoot` (Bölüme etiket verilmişse)
* **`ro`**: Kök dosya sistemini başlangıçta **salt okunur (read-only)** olarak bağlar. Başlatma sürecinin ilerleyen adımlarında genellikle `rw` (read-write) olarak yeniden bağlanır. Dosya sistemi kontrolü (fsck) için önemlidir.
* **`rw`**: Kök dosya sistemini başlangıçta **okunur-yazılır (read-write)** olarak bağlar. Genellikle sorun giderme dışında önerilmez.
* **`init=`**: `/sbin/init` yerine çalıştırılacak ilk kullanıcı alanı programını belirtir. Örneğin, `init=/bin/bash` komutu, sistem servislerini başlatmadan doğrudan bir root kabuğu açar (kurtarma modu için kullanılır).
* **`quiet`**: Açılış sırasında çekirdek tarafından ekrana yazdırılan mesajların çoğunu gizler. Daha "sessiz" bir açılış sağlar.
* **`splash`**: Grafiksel bir açılış ekranını (splash screen) etkinleştirir (eğer kurulu ve yapılandırılmışsa, örn. Plymouth). Genellikle `quiet` ile birlikte kullanılır.
* **`nomodeset`**: Çekirdeğin grafik kartı için mod ayarlamasını (Kernel Mode Setting - KMS) devre dışı bırakır. Bazı grafik kartı sürücüsü sorunlarında veya uyumsuzluklarında geçici bir çözüm olarak kullanılabilir, ancak genellikle grafik performansını düşürür.
* **`single` veya `1` veya `s`**: Sistemi tek kullanıcı (single-user) modunda başlatır. Genellikle kurtarma veya bakım işlemleri için kullanılır. systemd sistemlerde `systemd.unit=rescue.target` ile benzer bir işlev görülebilir.
* **`systemd.unit=`**: systemd init sistemi için varsayılan hedef (target) yerine belirli bir hedefi başlatmasını söyler. Kurtarma için kullanışlıdır:
  * `systemd.unit=rescue.target`: Tek kullanıcı moduna benzer, temel sistem ve kök dosya sistemi bağlanır.
  * `systemd.unit=emergency.target`: Daha da temel bir mod, sadece kök dosya sistemi salt okunur bağlanır ve acil durum kabuğu açılır.
* **`mem=`**: Çekirdeğin kullanabileceği maksimum RAM miktarını sınırlar (örn. `mem=4G`). Donanım testi veya uyumluluk için kullanılabilir.
* **`console=`**: Çekirdek mesajlarının gönderileceği konsol aygıtını ve seçeneklerini belirtir (örn. seri konsol için `console=ttyS0,115200n8`).

## Parametre Referansı

Çekirdek tarafından kabul edilen tüm parametrelerin tam listesi ve açıklamaları oldukça uzundur. Genellikle çekirdek kaynak kodu ile birlikte gelen `Documentation/admin-guide/kernel-parameters.txt` dosyasında veya [Kernel.org web sitesinde](https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html) bulunabilir. Belirli bir donanım veya alt sistem için parametreler, ilgili belgelerde de yer alabilir.


# Bootloader Nedir?

**Bootloader** (Önyükleyici), bilgisayarın donanım başlatma sürecini tamamlayan firmware (BIOS veya UEFI) ile işletim sistemi çekirdeği (kernel) arasında köprü görevi gören kritik bir yazılımdır. Firmware, donanımı test edip başlattıktan sonra, kontrolü önyükleyiciye devreder. Önyükleyicinin temel görevi, seçilen işletim sistemi çekirdeğini ve başlangıç için gerekli diğer dosyaları (genellikle initramfs) belleğe yüklemek ve ardından kontrolü çekirdeğe vermektir.

## Önyükleyicinin Görevleri

1. **İşletim Sistemi Seçimi:** Eğer sistemde birden fazla işletim sistemi veya aynı işletim sisteminin farklı çekirdek sürümleri kuruluysa, önyükleyici genellikle kullanıcıya bir menü sunarak hangisinin başlatılacağını seçme imkanı tanır.
2. **Çekirdek ve Initramfs Yükleme:** Seçilen işletim sistemine ait çekirdek imajını (`vmlinuz-...` gibi) ve başlangıç RAM dosya sistemini (`initramfs-...` veya `initrd-...`) depolama aygıtından (genellikle `/boot` dizininden) okuyarak belleğe (RAM) yükler.
3. **Çekirdek Parametrelerini Geçirme:** Çekirdeğin başlangıç davranışını etkileyen parametreleri (örneğin, kök dosya sisteminin konumu `root=`, salt okunur başlama `ro`, grafik mod ayarları, donanım seçenekleri vb.) çekirdeğe iletir. Bu parametreler genellikle önyükleyici menüsünden geçici olarak düzenlenebilir veya yapılandırma dosyasında kalıcı olarak ayarlanabilir.
4. **Kontrolü Çekirdeğe Devretme:** Gerekli dosyalar belleğe yüklendikten ve parametreler hazırlandıktan sonra, önyükleyici işlemciyi çekirdeğin başlangıç noktasına yönlendirerek kontrolü tamamen işletim sistemi çekirdeğine bırakır.

## Yaygın Önyükleyiciler

* **GRUB (GRand Unified Bootloader):** Linux dünyasındaki en yaygın önyükleyicidir. Özellikle **GRUB 2**, günümüzdeki çoğu dağıtım tarafından kullanılır. Hem BIOS hem de UEFI sistemleri destekler, esnek bir yapılandırmaya sahiptir ve birçok dosya sistemini okuyabilir. Yapılandırması genellikle `/boot/grub/grub.cfg` dosyasında bulunur, ancak bu dosya genellikle doğrudan düzenlenmez; bunun yerine `/etc/default/grub` dosyası ve `/etc/grub.d/` dizinindeki betikler düzenlenip `update-grub` veya `grub-mkconfig` komutları çalıştırılır.
* **systemd-boot (eski adıyla gummiboot):** Sadece **UEFI** sistemler için tasarlanmış, GRUB'a göre daha basit bir önyükleyicidir. Yapılandırması EFI Sistem Bölümü (ESP) içindeki metin dosyalarıyla (`/boot/loader/loader.conf`, `/boot/loader/entries/*.conf`) yapılır. Kurulumu ve yönetimi genellikle daha basittir.
* **LILO (LInux LOader):** Eski Linux sistemlerinde yaygın olan, ancak günümüzde büyük ölçüde GRUB tarafından yerini almış, daha basit bir önyükleyicidir. Genellikle MBR üzerine kurulur ve yapılandırması `/etc/lilo.conf` dosyasındadır.
* **SYSLINUX/EXTLINUX:** Özellikle CD/DVD veya USB belleklerden önyükleme yapmak için kullanılan bir önyükleyici ailesidir. `EXTLINUX`, ext2/3/4 veya btrfs gibi dosya sistemlerinden önyükleme yapmak için kullanılır.

Önyükleyici, sistemin doğru bir şekilde başlayabilmesi için hayati bir bileşendir. Yapılandırmasında yapılan hatalar sistemin açılmamasına neden olabilir.


# User Space

Çekirdek (kernel) başlatıldıktan ve temel donanım ayarlarını yaptıktan sonra, kontrolü kullanıcı alanındaki (user space) ilk işleme, yani **PID 1**'e devreder. Bu ilk işlem, **init sistemi** olarak bilinir ve görevi, sistemin geri kalanını (servisler, kullanıcı oturumları vb.) başlatmak ve yönetmektir.

Linux tarihinde farklı init sistemleri kullanılmıştır. Bu bölümde iki ana init sistemini inceleyeceğiz:

1. **System V init (SysVinit):** Geleneksel Unix init sistemidir. Betik tabanlıdır ve "runlevel" konseptini kullanır. Eski sistemlerde yaygın olarak kullanılmıştır, ancak modern dağıtımların çoğunda yerini systemd'ye bırakmıştır.
   * [System V](/user-space/system-v)
2. **systemd:** Modern Linux dağıtımlarının büyük çoğunluğu tarafından benimsenen, daha gelişmiş ve paralel başlatma yeteneklerine sahip bir sistem ve servis yöneticisidir. "Unit" dosyaları ve "target" konseptini kullanır.
   * [systemd](/user-space/systemd)

Ayrıca bu bölümde, çekirdekten init sistemine geçişte rol oynayan diğer kavramlara da değinilecektir:

* [Başlangıç: Init](/user-space/baslangic-init): PID 1'in rolü.
* [Init Versiyonunu Belirlemek](/user-space/init-versiyonunu-belirlemek): Sisteminizde hangi init sisteminin çalıştığını anlama.
* [Başlangıç RAM Dosya Sistemi](https://github.com/VeriTeknik/linux_kitap/blob/master/user-space/baslangic-ram-dosya-sistemi.md): Initramfs/initrd'nin user space başlangıcındaki rolü (Kernel Boot bölümüyle ilişkili).
* [Acil Durumlar ve Tek Kullanıcı Modu](/user-space/acil-durumlar-ve-tek-kullanici-modu): Sistem kurtarma modları.

Init sistemini anlamak, servislerin nasıl yönetildiğini, sistemin nasıl başladığını ve sorunların nasıl giderileceğini anlamak için kritik öneme sahiptir.


# Başlangıç: Init

Linux çekirdeği (kernel) başlatma işlemini tamamladıktan sonra, kontrolü kullanıcı alanındaki (user space) ilk sürece devreder. Bu ilk süreç her zaman **PID 1** (Process ID 1) olarak çalışır ve genellikle `/sbin/init` yoluyla başlatılır.

## PID 1'in Rolü

`init` süreci, sistemin temelini oluşturur ve kritik görevleri yerine getirir:

1. **Tüm Süreçlerin Atası:** Sistemdeki diğer tüm kullanıcı alanı süreçleri (servisler, kullanıcı oturumları, uygulamalar vb.) doğrudan veya dolaylı olarak `init` süreci tarafından başlatılır. Bu nedenle, `init` tüm süreçlerin en üst düzeydeki atasıdır. `pstree` komutu ile bu hiyerarşi görülebilir.
2. **Yetim Süreçleri Evlat Edinme (Orphan Process Adoption):** Normalde bir süreç (child process) sonlandığında, durumu üst süreci (parent process) tarafından okunur (reaping). Eğer bir üst süreç, alt süreci sonlanmadan önce kendisi sonlanırsa, alt süreç "yetim" (orphan) kalır. Bu durumda, yetim kalan süreç otomatik olarak `init` (PID 1) tarafından evlat edinilir. `init` süreci, evlat edindiği süreçler sonlandığında onların durumunu okuyarak sistemde "zombi" süreçlerin birikmesini engeller. (Zombi süreçler, sonlanmış ancak durumu üst süreci tarafından okunmamış süreçlerdir ve işlem tablosunda gereksiz yer kaplarlar).
3. **Sistemi Başlatma ve Durdurma:** `init` süreci, yapılandırmasına göre sistem servislerini belirli bir sıra ve bağımlılık ilişkisi içinde başlatır. Aynı şekilde, sistem kapatılırken veya yeniden başlatılırken servislerin düzgün bir şekilde durdurulmasından ve dosya sistemlerinin güvenli bir şekilde ayrılmasından (unmount) sorumludur.
4. **Sistem Durumunu Yönetme:** `init` sistemi, sistemin farklı çalışma durumlarını (örneğin, tek kullanıcı modu, çok kullanıcılı metin modu, grafiksel mod) yönetir ve bu durumlar arasında geçişi sağlar. Modern systemd'de bu "target" birimleri ile, eski SysVinit'te ise "runlevel"lar ile yapılır.

## `/sbin/init` ve Gerçek Init Sistemi

`/sbin/init` dosyası genellikle gerçek init sisteminin çalıştırılabilir dosyasına bir sembolik linktir. Modern sistemlerde bu link genellikle `/lib/systemd/systemd`'ye işaret eder. Eski sistemlerde ise doğrudan SysVinit'in `/sbin/init` dosyası olabilir. Çekirdek, varsayılan olarak `/sbin/init`'i çalıştırmaya çalışır, ancak bu davranış `init=` çekirdek parametresi ile değiştirilebilir (örneğin kurtarma modunda `init=/bin/bash` kullanmak gibi).

Hangi init sisteminin çalıştığını anlamak için [Init Versiyonunu Belirlemek](/user-space/init-versiyonunu-belirlemek) bölümüne bakabilirsiniz. `init` sürecinin kendisi sonlandırılırsa (ki bu genellikle engellenmiştir), sistem paniğe (kernel panic) girer ve durur, çünkü tüm süreçlerin temel dayanağı ortadan kalkmış olur.


# Init Versiyonunu Belirlemek

Linux sisteminizde hangi init sisteminin (PID 1 olarak çalışan ve sistemi başlatan süreç) kullanıldığını bilmek, servisleri yönetmek ve sistemin davranışını anlamak için önemlidir. Modern dağıtımların çoğu `systemd` kullanırken, eski sistemlerde `System V init` (SysVinit) veya `Upstart` gibi alternatifler bulunabilir.

İşte çalışan init sistemini belirlemek için kullanılabilecek bazı yaygın yöntemler:

1. **PID 1'in Komut Adını Kontrol Etme:**\
   En doğrudan yöntemlerden biri, PID 1 olarak çalışan sürecin komut adını kontrol etmektir:

   ```bash
   ps -p 1 -o comm=
   ```

   * Eğer çıktı `systemd` ise, sisteminiz systemd kullanıyor demektir.
   * Eğer çıktı `init` ise, genellikle SysVinit veya Upstart kullanılıyor demektir. (Upstart genellikle eski Ubuntu sürümlerinde bulunur).
2. **`/sbin/init` Sembolik Linkini Kontrol Etme:**\
   Çekirdek genellikle `/sbin/init`'i başlatır. Bu dosyanın nereye işaret ettiğini kontrol etmek init sistemini gösterebilir:

   ```bash
   ls -l /sbin/init
   ```

   * Eğer `/lib/systemd/systemd`'ye veya benzer bir yola işaret ediyorsa, systemd kullanılıyordur.
   * Eğer doğrudan `/sbin/init` çalıştırılabilir bir dosyaysa veya başka bir `init` dosyasına işaret ediyorsa, muhtemelen SysVinit veya Upstart'tır.
3. **`systemctl` Komutunun Varlığı ve Çalışması:**`systemctl` komutu, systemd'nin ana yönetim aracıdır. Bu komutun varlığı ve çalışması, systemd'nin kullanıldığının güçlü bir göstergesidir:

   ```bash
   systemctl status 
   # veya
   systemctl is-system-running
   ```

   Eğer bu komutlar systemd'ye özgü çıktılar veriyorsa veya hata vermeden çalışıyorsa, sisteminiz systemd kullanıyordur. SysVinit sistemlerde bu komut bulunmaz veya farklı davranır.
4. **`/etc/inittab` Dosyasını Kontrol Etme:**\
   Geleneksel SysVinit, ana yapılandırması için `/etc/inittab` dosyasını kullanır.

   ```bash
   ls /etc/inittab
   ```

   * Eğer bu dosya **varsa ve içinde runlevel tanımları gibi aktif yapılandırma satırları içeriyorsa**, sistem muhtemelen SysVinit kullanıyordur.
   * Modern systemd sistemlerinde `/etc/inittab` dosyası ya **bulunmaz** ya da sadece bilgilendirme amaçlı yorum satırları içeren **boş veya minimal** bir dosyadır.
5. **`runlevel` Komutunu Kontrol Etme:**\
   SysVinit sistemlerde mevcut çalışma seviyesini (runlevel) görmek için `runlevel` komutu kullanılır. systemd sistemlerde bu komut hala bulunabilir ancak genellikle farklı veya daha az anlamlı bir çıktı verir. systemd'de benzer işlev için `systemctl get-default` (varsayılan hedefi gösterir) veya `who -r` kullanılabilir.

Genellikle `ps -p 1 -o comm=` veya `ls -l /sbin/init` komutları, çalışan init sistemini hızlıca belirlemek için yeterlidir. Çoğu modern ve popüler Linux dağıtımı (Debian, Ubuntu, Fedora, RHEL, CentOS Stream, Arch Linux, SUSE vb.) artık varsayılan olarak systemd kullanmaktadır.


# System V

System V init (kısaca SysVinit), geleneksel Unix sistemlerinden miras kalan ve uzun yıllar boyunca birçok Linux dağıtımının varsayılan init sistemi olmuş bir başlangıç sistemidir. `/sbin/init` süreci (PID 1) olarak çalışır ve sistemi önceden tanımlanmış **çalışma seviyelerine (runlevels)** göre başlatmaktan ve yönetmekten sorumludur.

## Temel Özellikleri

* **Runlevel'lar:** Sistem farklı çalışma modlarını (runlevel) tanımlar (genellikle 0-6 arası). Örneğin, runlevel 0 sistemi kapatır, 1 tek kullanıcı modudur, 3 çok kullanıcılı metin modudur, 5 grafiksel moddur, 6 sistemi yeniden başlatır. Aktif runlevel `/etc/inittab` dosyasında (veya önyükleyici parametrelerinde) belirlenir.
* **Başlangıç Betikleri:** Her runlevel için çalıştırılacak veya durdurulacak servisler, genellikle `/etc/init.d/` (veya `/etc/rc.d/init.d/`) dizininde bulunan kabuk betikleri (shell scripts) ile yönetilir. Belirli bir runlevel'a girildiğinde, `/etc/rc<runlevel>.d/` (örn. `/etc/rc3.d/`) dizinindeki sembolik linkler aracılığıyla ilgili betikler çalıştırılır. `S` ile başlayan linkler servisleri başlatır (start), `K` ile başlayanlar durdurur (kill). Linklerdeki sayılar çalışma sırasını belirler.
* **Sıralı Başlatma:** SysVinit genellikle servisleri betiklerdeki sıra numaralarına göre büyük ölçüde sıralı olarak başlatır. Bu, modern sistemlerdeki paralel başlatmaya göre daha yavaş olabilir.
* **Servis Yönetimi:** Servisler genellikle `/etc/init.d/` altındaki betikler aracılığıyla (`/etc/init.d/<servis> start|stop|restart|status`) veya `service <servis> start|stop|...` komutuyla yönetilir. Servislerin başlangıçta otomatik çalışıp çalışmayacağı `chkconfig` (Red Hat tabanlı) veya `update-rc.d` (Debian tabanlı) gibi araçlarla yönetilir.

## Günümüzdeki Yeri

SysVinit, basitliği ve anlaşılırlığı nedeniyle hala bazı sistemlerde (özellikle eski veya gömülü sistemlerde) kullanılsa da, modern Linux dağıtımlarının büyük çoğunluğu (Debian, Ubuntu, Fedora, RHEL, CentOS Stream, Arch Linux vb.) varsayılan init sistemi olarak **systemd**'ye geçmiştir. systemd, paralel başlatma, daha iyi bağımlılık yönetimi, servis izleme ve daha gelişmiş özellikler sunar.

Bu bölümdeki diğer dosyalar, SysVinit'in temel kavramlarını (runlevel'lar, servis yönetimi) ve örnek bir servis betiğinin nasıl oluşturulacağını tarihsel bir bağlamda açıklamaktadır.


# Servislerin Yönetimi

System V init (SysVinit) sisteminde, arka planda çalışan servisler (daemon'lar) genellikle `/etc/init.d/` (veya RHEL tabanlı sistemlerde `/etc/rc.d/init.d/`) dizininde bulunan kabuk betikleri (shell scripts) aracılığıyla yönetilir.

## Init Betikleri

Bu betikler, genellikle aşağıdaki gibi standart argümanları kabul eder:

* `start`: Servisi başlatır.
* `stop`: Servisi durdurur.
* `restart`: Servisi durdurup yeniden başlatır.
* `reload`: Servisin yapılandırma dosyalarını yeniden yüklemesini sağlar (eğer destekliyorsa).
* `status`: Servisin çalışıp çalışmadığını kontrol eder.

Betikler doğrudan çalıştırılabilir (root yetkisiyle):

```bash
sudo /etc/init.d/apache2 start
sudo /etc/init.d/ssh status
```

## `service` Komutu

Çoğu SysVinit sisteminde, init betiklerini daha kolay yönetmek için bir `service` komutu bulunur. Bu komut, betiğin tam yolunu yazma ihtiyacını ortadan kaldırır:

```bash
sudo service apache2 start
sudo service ssh status
sudo service networking restart
```

## Servisleri Başlangıçta Etkinleştirme/Devre Dışı Bırakma

Bir servisin sistem açıldığında belirli bir çalışma seviyesinde (runlevel) otomatik olarak başlayıp başlamayacağı, `/etc/rc<runlevel>.d/` dizinlerindeki sembolik linkler aracılığıyla kontrol edilir. Bu linkleri yönetmek için dağıtıma özgü araçlar kullanılır:

* **RHEL/CentOS Tabanlı Sistemler (`chkconfig`):**

  ```bash
  # httpd servisini 2, 3, 4, 5 runlevel'larında etkinleştir
  sudo chkconfig httpd on 

  # httpd servisini tüm runlevel'larda devre dışı bırak
  sudo chkconfig httpd off

  # Servislerin durumunu listele
  sudo chkconfig --list 
  ```
* **Debian/Ubuntu Tabanlı Sistemler (`update-rc.d`):**

  ```bash
  # apache2 servisini varsayılan runlevel'larda etkinleştir
  sudo update-rc.d apache2 enable

  # apache2 servisini varsayılan runlevel'larda devre dışı bırak
  sudo update-rc.d apache2 disable

  # Belirli runlevel'lar için manuel link yönetimi (daha az yaygın)
  # sudo update-rc.d apache2 defaults # Varsayılan linkleri oluşturur
  # sudo update-rc.d apache2 remove  # Tüm linkleri kaldırır
  ```

  (Not: Eski Debian/Ubuntu sürümlerinde `sysv-rc-conf` gibi metin tabanlı araçlar da bulunabilir.)

SysVinit servis yönetimi, betiklere ve sembolik linklere dayanır. Modern systemd sistemlerindeki `systemctl` komutu, servis yönetimini daha merkezi ve standart hale getirmiştir.


# Çalışma Seviyeleri (Run Levels)

System V init (SysVinit), sistemi farklı çalışma modlarına veya durumlarına sokmak için **çalışma seviyeleri (runlevels)** konseptini kullanır. Her runlevel, hangi servislerin çalıştırılacağını veya durdurulacağını tanımlar. Sistem belirli bir runlevel'a geçtiğinde, o runlevel için tanımlanmış servisler başlatılırken, önceki runlevel'da çalışıp yeni runlevel'da tanımlı olmayan servisler durdurulur.

## Standart Runlevel'lar

Geleneksel olarak 7 runlevel (0'dan 6'ya kadar) tanımlanmıştır ve bunların çoğu için standartlaşmış anlamlar bulunur, ancak dağıtımlar arasında küçük farklılıklar olabilir:

* **Runlevel 0: Halt (Durdurma)**
  * Sistemi güvenli bir şekilde kapatır. Bu runlevel'a geçmek, `shutdown -h now` veya `halt` komutlarına benzer.
* **Runlevel 1: Single-User Mode (Tek Kullanıcı Modu)**
  * Sistemi bakım ve kurtarma işlemleri için minimal bir modda başlatır. Genellikle ağ servisleri çalışmaz ve sadece root kullanıcısı giriş yapabilir. Kök dosya sistemi genellikle salt okunur (read-only) olarak bağlanabilir.
* **Runlevel 2: Multi-User Mode (Çok Kullanıcılı Mod - Ağsız)**
  * Debian tabanlı sistemlerde: Ağ servisleri *olmadan* çok kullanıcılı metin modu.
  * RHEL tabanlı sistemlerde: Genellikle Runlevel 3 ile aynıdır (ağ destekli çok kullanıcılı metin modu).
* **Runlevel 3: Multi-User Mode with Networking (Ağ Destekli Çok Kullanıcılı Mod)**
  * Tamamen işlevsel, ağ destekli, komut satırı tabanlı çok kullanıcılı mod. Sunucular için **yaygın varsayılan** runlevel'dır.
* **Runlevel 4: Unused/Custom (Kullanılmayan/Özel)**
  * Genellikle sistem yöneticisi tarafından özel amaçlar için tanımlanmak üzere boş bırakılır.
* **Runlevel 5: Multi-User Mode with Graphical Interface (Grafik Arayüzlü Çok Kullanıcılı Mod)**
  * Runlevel 3'teki her şeye ek olarak grafiksel bir ekran yöneticisi (örn. GDM, KDM, LightDM) başlatılır. Masaüstü sistemler için **yaygın varsayılan** runlevel'dır.
* **Runlevel 6: Reboot (Yeniden Başlatma)**
  * Sistemi güvenli bir şekilde yeniden başlatır. Bu runlevel'a geçmek, `shutdown -r now` veya `reboot` komutlarına benzer.

## Runlevel Yönetimi

* **Varsayılan Runlevel:** Sistemin normalde hangi runlevel'da başlayacağı genellikle `/etc/inittab` dosyasındaki `id:N:initdefault:` satırı ile belirlenir (burada N varsayılan runlevel numarasıdır, örn. 3 veya 5). Bazı modern SysVinit sistemleri veya önyükleyiciler bu ayarı farklı yerlerde tutabilir (örn. GRUB çekirdek parametresi).
* **Mevcut Runlevel'ı Görme:** `runlevel` komutu, önceki ve mevcut runlevel'ı gösterir. Çıktıdaki ilk karakter önceki (eğer yoksa 'N'), ikinci karakter mevcut runlevel'dır.

  ```bash
  runlevel
  # Örnek Çıktı: N 3 
  ```
* **Runlevel Değiştirme:** Çalışan sistemin runlevel'ını değiştirmek için `init` veya `telinit` komutları kullanılır (root yetkisiyle).

  ```bash
  # Runlevel 3'e geç
  sudo init 3 

  # Tek kullanıcı moduna geç (Runlevel 1)
  sudo telinit 1 
  ```

Runlevel konsepti, systemd'deki **target** birimleri ile benzer bir amaca hizmet eder, ancak systemd target'ları daha esnek ve bağımlılık tabanlı bir yapı sunar.


# Örnek System V Servis Oluşturma

System V init (SysVinit) sisteminde, servisler `/etc/init.d/` (veya `/etc/rc.d/init.d/`) dizininde bulunan kabuk betikleri (shell scripts) ile yönetilir. Bu betikler, servisi başlatmak (`start`), durdurmak (`stop`), yeniden başlatmak (`restart`) ve durumunu sorgulamak (`status`) gibi eylemleri gerçekleştiren mantığı içerir.

Aşağıda, basit bir servisi yönetmek için temel bir SysVinit betiği iskeleti verilmiştir. Bu betik, `/usr/local/bin/benimservisim` adlı bir programı `benimkullanici` kullanıcısı olarak çalıştırdığını varsayar ve PID dosyasını `/var/run/benimservisim.pid` olarak kullanır.

```bash
#!/bin/sh
### BEGIN INIT INFO
# Provides:          benimservisim
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Benim örnek servisimi başlatır/durdurur
# Description:       Bu betik, /usr/local/bin/benimservisim daemon'ını yönetir.
### END INIT INFO

# Betik değişkenleri
DAEMON=/usr/local/bin/benimservisim
DAEMON_ARGS="" # Daemon'a geçilecek argümanlar (varsa)
NAME=benimservisim
DESC="Benim Örnek Servisim"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
RUNASUSER=benimkullanici # Servisi çalıştıracak kullanıcı

# Dağıtıma özgü fonksiyon kütüphanesini yükle
# Debian/Ubuntu:
. /lib/lsb/init-functions
# RHEL/CentOS:
# . /etc/rc.d/init.d/functions 

# Yardımcı fonksiyonlar (start-stop-daemon Debian/Ubuntu'da yaygındır)
do_start() {
    # start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $RUNASUSER --exec $DAEMON --test > /dev/null || return 1
    # start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $RUNASUSER --exec $DAEMON -- $DAEMON_ARGS || return 2
    # Alternatif (daha basit, start-stop-daemon yoksa):
    if [ -f $PIDFILE ]; then
        log_daemon_msg "$DESC zaten çalışıyor" "$NAME"
        log_end_msg 0
        return 1
    fi
    log_daemon_msg "$DESC başlatılıyor" "$NAME"
    su -s /bin/sh -c "$DAEMON $DAEMON_ARGS & echo \$! > $PIDFILE" $RUNASUSER
    log_end_msg $?
}

do_stop() {
    # start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
    # RETVAL="$?"
    # [ "$RETVAL" = 2 ] && return 2
    # start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
    # [ "$?" = 2 ] && return 2
    # rm -f $PIDFILE
    # return "$RETVAL"
    # Alternatif (daha basit):
    if [ ! -f $PIDFILE ]; then
        log_daemon_msg "$DESC zaten durdurulmuş" "$NAME"
        log_end_msg 0
        return 1
    fi
    log_daemon_msg "$DESC durduruluyor" "$NAME"
    PID=$(cat $PIDFILE)
    kill $PID
    # kill komutunun başarılı olup olmadığını kontrol et (daha gelişmiş kontrol eklenebilir)
    sleep 1 # Durması için biraz bekle
    rm -f $PIDFILE
    log_end_msg $?
}

case "$1" in
  start)
    do_start
    ;;
  stop)
    do_stop
    ;;
  status)
    # status_of_proc -p $PIDFILE "$DAEMON" "$NAME" && exit 0 || exit $?
    # Alternatif (daha basit):
    if [ -f $PIDFILE ]; then
        PID=$(cat $PIDFILE)
        if ps -p $PID > /dev/null; then
            log_daemon_msg "$DESC çalışıyor (PID $PID)" "$NAME"
            log_end_msg 0
            exit 0
        else
            log_daemon_msg "$DESC çalışmıyor ama PID dosyası ($PIDFILE) mevcut" "$NAME"
            log_end_msg 1
            exit 1
        fi
    else
        log_daemon_msg "$DESC çalışmıyor" "$NAME"
        log_end_msg 3
        exit 3
    fi
    ;;
  restart|force-reload)
    log_daemon_msg "$DESC yeniden başlatılıyor" "$NAME"
    do_stop
    # Durması için biraz bekle
    sleep 1 
    do_start
    ;;
  *)
    echo "Kullanım: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
    exit 3
    ;;
esac

exit 0
```

**Açıklamalar:**

* **LSB Headers (`### BEGIN INIT INFO ... ### END INIT INFO`):** Bu başlıklar, `update-rc.d` ve `chkconfig` gibi araçların betik hakkında bilgi (bağımlılıklar, varsayılan runlevel'lar vb.) edinmesini sağlar. İsteğe bağlıdır ancak iyi bir pratiktir.
* **Fonksiyon Kütüphanesi:** Dağıtımlar genellikle servis betiklerinde kullanılmak üzere standart fonksiyonlar (`log_daemon_msg`, `log_end_msg`, `status_of_proc` vb.) içeren bir kütüphane sağlar. Bu, betiklerin daha tutarlı ve okunabilir olmasını sağlar. Örnekte hem Debian/Ubuntu (`/lib/lsb/init-functions`) hem de RHEL/CentOS (`/etc/rc.d/init.d/functions`) için kaynak satırı yorum olarak gösterilmiştir. Ayrıca `start-stop-daemon` (Debian/Ubuntu) gibi yardımcı programlar da kullanılabilir. Örnekte daha basit, genel komutlarla (`su`, `kill`, `ps`) alternatifler de gösterilmiştir.
* **`case "$1" in ... esac`:** Betiğe verilen ilk argümana (`start`, `stop` vb.) göre ilgili fonksiyonu (`do_start`, `do_stop`) çağırır.
* **PID Dosyası:** Servisin işlem ID'sini (PID) saklamak için genellikle `/var/run/` altında bir `.pid` dosyası kullanılır. Bu, servisin durumunu kontrol etmek ve durdurmak için kullanılır.
* **Kullanıcı Değiştirme:** Servisler genellikle root olarak başlatılmaz. `su` veya `start-stop-daemon --chuid` gibi komutlarla belirtilen kullanıcıya (`RUNASUSER`) geçiş yapılır.

**Kullanım:**

1. Betiği `/etc/init.d/benimservisim` olarak kaydedin.
2. Çalıştırma izni verin: `sudo chmod +x /etc/init.d/benimservisim`.
3. Servisi yönetin:

   ```bash
   sudo service benimservisim start
   sudo service benimservisim status
   sudo service benimservisim stop
   ```
4. Başlangıçta otomatik çalışması için etkinleştirin:

   ```bash
   # Debian/Ubuntu
   sudo update-rc.d benimservisim defaults 
   # veya
   # sudo update-rc.d benimservisim enable

   # RHEL/CentOS
   sudo chkconfig --add benimservisim
   sudo chkconfig benimservisim on 
   ```

Bu, SysVinit için temel bir servis betiği örneğidir. Gerçek dünya betikleri genellikle daha karmaşık hata kontrolü ve yapılandırma seçenekleri içerir. Modern systemd sistemlerinde servis yönetimi için `.service` unit dosyaları kullanılır ve bu genellikle daha basit ve güçlü bir yöntemdir.


# systemd

`systemd`, modern Linux dağıtımlarının büyük çoğunluğu tarafından benimsenen gelişmiş bir **sistem ve servis yöneticisidir**. Geleneksel System V init (SysVinit) sisteminin yerini almıştır ve PID 1 olarak çalışarak sistemi başlatmaktan, servisleri yönetmekten ve sistemin genel durumunu denetlemekten sorumludur.

## Temel Kavramlar ve Özellikler

* **Unit Dosyaları:** systemd, yönettiği kaynakları (servisler, mount noktaları, cihazlar, soketler vb.) **unit** adı verilen yapılandırma dosyaları aracılığıyla tanımlar. Bu dosyalar genellikle `.service`, `.socket`, `.mount`, `.target` gibi uzantılara sahiptir ve `/usr/lib/systemd/system/` (dağıtım tarafından sağlananlar) veya `/etc/systemd/system/` (sistem yöneticisi tarafından oluşturulan veya düzenlenenler) dizinlerinde bulunur. Unit dosyaları, basit bir `INI` benzeri sözdizimine sahiptir.
  * [Birimler ve Birim Tipleri](/user-space/systemd/birimler-ve-birim-tipleri)
* **Servis Yönetimi (`systemctl`):** Servisleri (ve diğer unit'leri) yönetmek için ana komut `systemctl`'dir. Servisleri başlatma, durdurma, yeniden başlatma, durumunu kontrol etme, başlangıçta etkinleştirme/devre dışı bırakma gibi işlemler bu komutla yapılır.
  * [Servislerin Yönetimi](/user-space/systemd/servislerin-yoenetimi)
* **Target Birimleri:** SysVinit'teki runlevel konseptinin yerini alan **target** birimleri, sistemin belirli bir çalışma durumunu veya hedefini temsil eder. Target'lar, diğer unit'leri gruplayarak belirli bir amaca hizmet eden bir dizi servisin başlatılmasını sağlar (örn. `multi-user.target`, `graphical.target`, `rescue.target`).
* **Paralel Başlatma:** systemd, servisler arasındaki bağımlılıkları analiz ederek mümkün olduğunca çok servisi aynı anda (paralel olarak) başlatmaya çalışır. Bu, genellikle SysVinit'in sıralı başlatmasına göre daha hızlı bir sistem açılışı sağlar.
* **Soket Aktivasyonu:** Servisler, ilgili sokete bir bağlantı geldiğinde otomatik olarak başlatılabilir. Bu, servisin sürekli çalışmasına gerek kalmadan kaynak tasarrufu sağlar.
* **Günlük Yönetimi (Journald):** systemd, sistem ve servis günlüklerini merkezi ve yapılandırılmış bir şekilde toplayan ve yöneten `journald` servisini içerir. Günlüklere `journalctl` komutu ile erişilir.
* **Diğer Bileşenler:** systemd ayrıca `systemd-networkd` (ağ yönetimi), `systemd-resolved` (DNS çözümleme), `systemd-timesyncd` (zaman senkronizasyonu), `systemd-logind` (kullanıcı oturum yönetimi) gibi birçok alt bileşen içerir.

## Avantajları

* Daha hızlı sistem açılışı (paralel başlatma).
* Daha gelişmiş ve esnek servis bağımlılık yönetimi.
* Servislerin daha iyi izlenmesi ve otomatik yeniden başlatılması.
* Merkezi ve yapılandırılmış günlük kaydı (journald).
* Cgroups aracılığıyla kaynak yönetimi entegrasyonu.
* Daha standart ve güçlü servis yönetim komutları (`systemctl`).

systemd, modern Linux sistem yönetiminin temel taşı haline gelmiştir ve komutlarını ve kavramlarını anlamak, sistem yöneticileri için önemlidir. Bu bölümdeki diğer dosyalar, systemd'nin temel bileşenlerini ve kullanımını daha detaylı olarak ele alacaktır.


# Servislerin Yönetimi

`systemd` init sisteminde, servisleri ve diğer sistem birimlerini (units) yönetmek için kullanılan ana komut `systemctl`'dir. Bu komut, eski `service`, `chkconfig`, `update-rc.d` gibi araçların işlevlerini birleştirir ve daha tutarlı bir arayüz sunar. Komutların çoğu `sudo` yetkisi gerektirir.

## Temel Servis Yönetimi Komutları

Aşağıda `<servis_adı>` yerine yönetmek istediğiniz servisin adını (örn. `sshd`, `nginx`, `apache2`) yazmalısınız. `.service` uzantısı genellikle isteğe bağlıdır.

* **Servisi Başlatma (`start`):**\
  Bir servisi hemen başlatır.

  ```bash
  sudo systemctl start <servis_adı>
  ```
* **Servisi Durdurma (`stop`):**\
  Çalışan bir servisi hemen durdurur.

  ```bash
  sudo systemctl stop <servis_adı>
  ```
* **Servisi Yeniden Başlatma (`restart`):**\
  Servisi durdurur ve ardından yeniden başlatır. Yapılandırma değişikliklerinden sonra veya servisin takılması durumunda kullanılır.

  ```bash
  sudo systemctl restart <servis_adı>
  ```
* **Yapılandırmayı Yeniden Yükleme (`reload`):**\
  Servise, yapılandırma dosyalarını yeniden okumasını söyler. Bu işlem genellikle servisi durdurmadan yapılır, ancak tüm servisler `reload` işlemini desteklemez.

  ```bash
  sudo systemctl reload <servis_adı>
  ```

  Eğer servis `reload` desteklemiyorsa, genellikle `restart` kullanmak gerekir.
* **Koşullu Yeniden Başlatma (`try-restart`):**\
  Sadece servis zaten çalışıyorsa yeniden başlatır.

  ```bash
  sudo systemctl try-restart <servis_adı>
  ```
* **Koşullu Yeniden Yükleme (`reload-or-restart`):**\
  Servis `reload` destekliyorsa yeniden yükler, desteklemiyorsa yeniden başlatır.

  ```bash
  sudo systemctl reload-or-restart <servis_adı>
  ```

## Servis Durumunu Kontrol Etme

* **Detaylı Durum (`status`):**\
  Bir servisin mevcut durumunu (aktif/pasif, etkin/devre dışı), PID'sini, bellek/CPU kullanımını ve en son günlük (log) mesajlarını gösterir.

  ```bash
  systemctl status <servis_adı>
  ```

  Çıktıdan `q` tuşu ile çıkılır.
* **Aktif mi? (`is-active`):**\
  Servisin o anda çalışıp çalışmadığını kontrol eder. Genellikle betiklerde kullanılır. Çıktısı `active` veya `inactive` (veya `activating`, `failed` vb.) olur.

  ```bash
  systemctl is-active <servis_adı>
  ```
* **Başlangıçta Etkin mi? (`is-enabled`):**\
  Servisin sistem başlangıcında otomatik olarak çalışacak şekilde etkinleştirilip etkinleştirilmediğini kontrol eder. Çıktısı `enabled`, `disabled`, `static` (manuel olarak başlatılamaz/durdurulamaz ama başka unit'ler tarafından kullanılabilir), `masked` vb. olur.

  ```bash
  systemctl is-enabled <servis_adı>
  ```
* **Başarısız mı? (`is-failed`):**\
  Servisin hata durumunda olup olmadığını kontrol eder.

  ```bash
  systemctl is-failed <servis_adı>
  ```

## Servisleri Başlangıçta Etkinleştirme/Devre Dışı Bırakma

* **Etkinleştirme (`enable`):**\
  Bir servisin sistem başlangıcında otomatik olarak çalışmasını sağlar. Gerekli sembolik linkleri oluşturur.

  ```bash
  sudo systemctl enable <servis_adı>
  ```

  `--now` seçeneği ile hem etkinleştirip hem de hemen başlatabilirsiniz:

  ```bash
  sudo systemctl enable --now <servis_adı>
  ```
* **Devre Dışı Bırakma (`disable`):**\
  Bir servisin sistem başlangıcında otomatik olarak çalışmasını engeller. Gerekli sembolik linkleri kaldırır. Servis o anda çalışıyorsa durdurmaz.

  ```bash
  sudo systemctl disable <servis_adı>
  ```

  `--now` seçeneği ile hem devre dışı bırakıp hem de hemen durdurabilirsiniz:

  ```bash
  sudo systemctl disable --now <servis_adı>
  ```
* **Maskeleme (`mask`):**\
  Bir servisi tamamen devre dışı bırakır. Servis manuel olarak veya başka bir servisin bağımlılığı olarak bile başlatılamaz. Bu işlem, genellikle `/etc/systemd/system/` altına servisin unit dosyasını `/dev/null`'a yönlendiren bir sembolik link oluşturarak yapılır.

  ```bash
  sudo systemctl mask <servis_adı>
  ```
* **Maskeyi Kaldırma (`unmask`):**\
  Maskelenmiş bir servisin maskesini kaldırır, ancak servisi otomatik olarak etkinleştirmez.

  ```bash
  sudo systemctl unmask <servis_adı>
  ```

`systemctl`, systemd sistemlerde servisleri ve diğer unit'leri yönetmek için merkezi ve güçlü bir araçtır.


# Birimler ve Birim Tipleri

`systemd`, yönettiği tüm kaynakları ve eylemleri **birim (unit)** adı verilen nesneler aracılığıyla tanımlar. Her birim, belirli bir türdeki bir kaynağı veya görevi temsil eder ve bir yapılandırma dosyası (unit file) ile tanımlanır. Bu dosyalar, sistemin nasıl başlatılacağını, servislerin nasıl çalışacağını, cihazların nasıl yönetileceğini ve diğer birçok sistem davranışını belirler.

## Birim Dosyalarının Konumları

Birim dosyaları genellikle aşağıdaki dizinlerde bulunur ve belirli bir öncelik sırasına göre okunur:

1. **/etc/systemd/system/:** Sistem yöneticisi tarafından oluşturulan veya düzenlenen birim dosyaları. Buradaki dosyalar, diğer dizinlerdeki aynı isimli dosyaları geçersiz kılar (override eder) veya tamamlar. Özel servisler veya varsayılan davranışları değiştirmek için kullanılır.
2. **/run/systemd/system/:** Çalışma zamanında (runtime) oluşturulan birim dosyaları. `/etc/`'deki dosyalara göre önceliklidir.
3. **/usr/lib/systemd/system/:** Kurulan paketler tarafından sağlanan varsayılan birim dosyaları (vendor-supplied). Bu dosyalar doğrudan düzenlenmemelidir; değişiklik yapmak için dosya `/etc/systemd/system/` altına kopyalanmalı veya `systemctl edit <unit>` komutu kullanılmalıdır.

`systemd`, bir unit'i yüklerken bu dizinleri belirtilen sırayla kontrol eder ve bulduğu ilk eşleşmeyi kullanır.

## Yaygın Birim Tipleri

Birim dosyalarının adları, temsil ettikleri kaynağın türünü belirten bir uzantı ile biter. En yaygın birim tipleri şunlardır:

* **`.service`:** Sistem servislerini (daemon'ları) tanımlar. En sık kullanılan birim tipidir. Bir servisin nasıl başlatılacağını, durdurulacağını, hangi kullanıcıyla çalışacağını, bağımlılıklarını ve diğer davranışlarını belirler. (Örn: `sshd.service`, `nginx.service`)
* **`.socket`:** Bir ağ soketini, IPC soketini veya FIFO'yu temsil eder. Genellikle **soket aktivasyonu** için kullanılır; yani ilgili sokete bir bağlantı geldiğinde, systemd ilişkili `.service` birimini otomatik olarak başlatır. Bu, servisin sürekli çalışmasına gerek kalmadan kaynak tasarrufu sağlar. (Örn: `sshd.socket`)
* **`.target`:** Diğer unit'leri gruplayan bir senkronizasyon noktasıdır. Belirli bir sistem durumunu veya hedefini temsil eder. SysVinit'teki runlevel'lara benzer bir işlev görür, ancak daha esnektir ve bağımlılıklara dayanır. (Örn: `multi-user.target`, `graphical.target`, `network.target`, `sysinit.target`)
* **`.mount`:** Bir dosya sistemi bağlama noktasını (`/etc/fstab`'daki bir satıra benzer şekilde) tanımlar ve yönetir. systemd, `/etc/fstab` girdilerini de otomatik olarak `.mount` birimlerine dönüştürebilir. (Örn: `home.mount`)
* **`.automount`:** Bir dosya sistemi bağlama noktası için otomatik bağlama (automount) işlevselliği sağlar. İlgili dizine erişildiğinde, systemd ilişkili `.mount` birimini otomatik olarak etkinleştirir. Ağ paylaşımları veya isteğe bağlı bağlanan aygıtlar için kullanışlıdır. (Örn: `media-usb.automount`)
* **`.timer`:** Belirli zamanlarda veya periyodik olarak başka bir unit'i (genellikle bir `.service` unit'ini) etkinleştirmek için kullanılır. `cron` işlerine modern bir alternatiftir. (Örn: `backup.timer`)
* **`.path`:** Belirli bir dosya veya dizindeki değişiklikleri izler ve bir değişiklik olduğunda (örn. dosya oluşturma, değiştirme) başka bir unit'i etkinleştirir. (Örn: `logwatch.path`)
* **`.slice`:** Kaynak yönetimi için kullanılan bir gruplama mekanizmasıdır. Linux Kontrol Grupları (cgroups) ile ilişkilidir ve bir grup unit'in toplam kaynak kullanımını (CPU, bellek, I/O vb.) sınırlamak veya yönetmek için kullanılır. (Örn: `user.slice`, `system.slice`)
* **`.scope`:** `slice`'a benzer, ancak systemd tarafından başlatılmayan, dışarıdan oluşturulan süreçleri (örn. kullanıcı oturumları, `sshd` tarafından başlatılan süreçler) gruplamak için kullanılır. Kaynak yönetimi ve izleme amacıyla kullanılır.
* **`.device`:** Çekirdek tarafından algılanan ve `udev` tarafından systemd'ye bildirilen donanım aygıtlarını temsil eder. Genellikle otomatik olarak oluşturulur ve bağımlılıklar için kullanılır.

## Birimleri `systemctl` ile Yönetme

`systemctl` komutu sadece servisleri değil, tüm unit tiplerini yönetmek için kullanılır.

* **Unit'leri Listeleme:**

  ```bash
  # Aktif olan tüm unit'leri listele
  systemctl list-units

  # Belirli bir tipteki unit'leri listele (örn. servisler)
  systemctl list-units --type=service

  # Tüm unit'leri (aktif olmayanlar dahil) listele
  systemctl list-units --all 
  ```
* **Unit Dosyalarını Listeleme:**\
  Sistemdeki tüm unit dosyalarını ve durumlarını (enabled, disabled, static, masked) listeler.

  ```bash
  systemctl list-unit-files
  ```
* **Unit Dosyasının İçeriğini Görme:**

  ```bash
  systemctl cat sshd.service
  ```
* **Unit'in Detaylı Özelliklerini Görme:**

  ```bash
  systemctl show sshd.service
  ```
* **Bağımlılıkları Görme:**

  ```bash
  # Bir unit'in hangi unit'lere bağımlı olduğunu göster
  systemctl list-dependencies sshd.service

  # Bir unit'in hangi unit'ler tarafından istendiğini göster (ters bağımlılık)
  systemctl list-dependencies --reverse sshd.service 
  ```

Unit dosyaları ve tipleri, systemd'nin esnekliğinin ve gücünün temelini oluşturur. Bir servisin veya sistem davranışının nasıl çalıştığını anlamak için ilgili unit dosyalarını incelemek önemlidir.


# Örnek systemd Servis Oluşturma

Kendi yazdığınız bir uygulamayı veya paket yöneticisiyle kurulduğunda otomatik olarak bir servis birimi (unit) oluşturmayan bir yazılımı systemd ile yönetmek için özel bir `.service` birim dosyası oluşturabilirsiniz.

## Birim Dosyasının Konumu

Sistem yöneticisi tarafından oluşturulan özel birim dosyaları genellikle `/etc/systemd/system/` dizinine yerleştirilir. Dosya adı, servisin adıyla aynı olmalı ve `.service` uzantısıyla bitmelidir (örn. `/etc/systemd/system/benimuygulamam.service`).

## Örnek `.service` Dosyası

Aşağıda, `/opt/benimuygulamam/app.py` adresindeki bir Python uygulamasını `uygulama_user` kullanıcısı olarak çalıştıran basit bir servis birimi örneği verilmiştir:

```ini
[Unit]
Description=Benim Özel Uygulama Servisim
After=network.target # Ağ bağlantısı hazır olduktan sonra başlasın

[Service]
# Çalıştırılacak Kullanıcı ve Grup
User=uygulama_user
Group=uygulama_group

# Çalışma Dizini
WorkingDirectory=/opt/benimuygulamam/

# Çalıştırılacak Ana Komut
ExecStart=/usr/bin/python3 /opt/benimuygulamam/app.py --config /etc/benimuygulamam.conf

# Yeniden Başlatma Politikası (örn. hata durumunda)
Restart=on-failure 
# Diğer seçenekler: no, always, on-success, on-abnormal, on-abort

# Servis Tipi (daemon olmayan basit süreçler için 'simple' yeterlidir)
Type=simple 

# (İsteğe Bağlı) Başlamadan önce çalıştırılacak komut
# ExecStartPre=/opt/benimuygulamam/hazirlik_betigi.sh

# (İsteğe Bağlı) Durdurulduktan sonra çalıştırılacak komut
# ExecStopPost=/opt/benimuygulamam/temizlik_betigi.sh

[Install]
WantedBy=multi-user.target # Hangi hedef (target) etkinleştirildiğinde bu servisin de etkinleştirileceğini belirtir
                           # multi-user.target genellikle metin tabanlı çok kullanıcılı sistemler için kullanılır
```

**Açıklamalar:**

* **`[Unit]` Bölümü:**
  * `Description`: Servisin ne işe yaradığını açıklayan kısa bir metin. `systemctl status` çıktısında görünür.
  * `After`: Bu servisin başlamadan önce hangi diğer unit'lerin (servisler, target'lar vb.) başlamış olması gerektiğini belirtir. Bağımlılıkları tanımlar. `network.target` ağın hazır olduğunu, `syslog.target` günlüklemenin hazır olduğunu belirtmek için sıkça kullanılır. `Wants` veya `Requires` gibi başka bağımlılık türleri de vardır.
* **`[Service]` Bölümü:**
  * `User`, `Group`: Servisin hangi kullanıcı ve grup kimliğiyle çalıştırılacağını belirtir. Güvenlik açısından root olmayan özel bir kullanıcı oluşturmak genellikle iyi bir pratiktir.
  * `WorkingDirectory`: `ExecStart` komutunun çalıştırılacağı dizini belirtir.
  * `ExecStart`: Servisi başlatmak için çalıştırılacak ana komutu ve argümanlarını belirtir. Komutun tam yolu yazılmalıdır.
  * `Restart`: Servis beklenmedik bir şekilde durduğunda systemd'nin onu yeniden başlatıp başlatmayacağını ve hangi koşullarda başlatacağını belirler.
  * `Type`: Servisin başlangıç davranışını belirtir. `simple` (varsayılan), `forking` (eski daemon'lar için), `oneshot` (tek seferlik görevler için), `notify` (servis hazır olduğunda systemd'ye bildirim gönderir) gibi tipler bulunur.
  * `ExecStartPre`, `ExecStartPost`, `ExecStop`, `ExecStopPost`: Servis yaşam döngüsünün farklı aşamalarında çalıştırılacak ek komutları tanımlar.
* **`[Install]` Bölümü:**
  * `WantedBy`: `systemctl enable` komutu çalıştırıldığında, bu servisin hangi target birimi için etkinleştirileceğini (yani hangi target başlatıldığında bu servisin de başlatılacağını) belirtir. Çoğu ağ servisi için `multi-user.target` uygun bir değerdir. Grafiksel uygulamalarla ilgili servisler `graphical.target` kullanabilir.

## Birim Dosyasını Kullanma

1. Yukarıdaki içeriği `/etc/systemd/system/benimuygulamam.service` gibi bir dosyaya kaydedin.
2. Dosya izinlerini ayarlayın (genellikle `644` yeterlidir): `sudo chmod 644 /etc/systemd/system/benimuygulamam.service`.
3. systemd'nin yeni veya değiştirilmiş birim dosyasını tanıması için daemon'u yeniden yükleyin:

   ```bash
   sudo systemctl daemon-reload
   ```
4. Servisi başlangıçta çalışacak şekilde etkinleştirin ve hemen başlatın:

   ```bash
   sudo systemctl enable --now benimuygulamam.service
   ```
5. Servisin durumunu kontrol edin:

   ```bash
   systemctl status benimuygulamam.service
   ```

Artık özel uygulamanız bir systemd servisi olarak yönetilebilir. Detaylı bilgi ve tüm seçenekler için `systemd.unit(5)`, `systemd.service(5)`, `systemd.exec(5)` gibi man sayfalarına bakabilirsiniz.


# Acil Durumlar ve Tek Kullanıcı Modu

Bazen bir Linux sistemini normal şekilde başlatmak mümkün olmayabilir veya sistem üzerinde bakım yapmak için normal çalışma moduna girmeden müdahale etmek gerekebilir. Bu gibi durumlar için çeşitli kurtarma modları mevcuttur. En yaygın olanı **tek kullanıcı modu (single-user mode)**'dur.

## Neden Kurtarma Moduna İhtiyaç Duyulur?

* Root şifresini unutmak ve sıfırlamak.
* Bozulmuş bir dosya sistemini kontrol etmek ve onarmak (`fsck`).
* Sistemin açılmasını engelleyen hatalı bir yapılandırma dosyasını düzeltmek (örn. `/etc/fstab`, `/etc/ssh/sshd_config`).
* Normal açılışı engelleyen bir servisi devre dışı bırakmak.
* Donanım veya sürücü sorunlarını teşhis etmek.

## Kurtarma Moduna Nasıl Girilir?

Kurtarma moduna girmek için genellikle önyükleyici (bootloader) menüsüne müdahale etmek ve çekirdek parametrelerini geçici olarak düzenlemek gerekir.

1. **Önyükleyici Menüsünü Açma:** Sistemi başlatırken önyükleyici menüsünü (genellikle GRUB) görüntülemek için doğru tuşa basın. Bu tuş genellikle BIOS/UEFI ekranından hemen sonra `Shift` (özellikle Ubuntu'da) veya `ESC` olabilir. Bazen menü varsayılan olarak görünür.
2. **Önyükleme Girdisini Düzenleme:** Menüde, normalde başlattığınız Linux girdisini seçin (üzerine gelin) ve düzenleme moduna girmek için belirtilen tuşa basın (GRUB'da genellikle `e` tuşudur).
3. **Çekirdek Parametresini Ekleme/Değiştirme:** Ekranda önyükleme komutları görünecektir. `linux` veya `linuxefi` ile başlayan satırı bulun. Bu satırın sonuna (genellikle `ro quiet splash` gibi parametrelerden sonra) bir boşluk bırakarak aşağıdaki parametrelerden uygun olanı ekleyin:
   * **SysVinit Sistemler İçin:**
     * `single` veya `1`: Sistemi runlevel 1'e (tek kullanıcı modu) başlatır.
   * **systemd Sistemler İçin (Önerilenler):**
     * `systemd.unit=rescue.target`: Tek kullanıcı moduna benzer. Temel sistemi başlatır, dosya sistemlerini (genellikle okunur-yazılır) bağlar ve bir kurtarma kabuğu (root shell) sunar. Ağ genellikle aktif olmaz.
     * `systemd.unit=emergency.target`: Daha da minimal bir moddur. Sadece kök dosya sistemini salt okunur (read-only) olarak bağlar ve bir acil durum kabuğu sunar. Dosya sistemi onarımı gibi işlemler için kullanışlıdır.
   * **Doğrudan Kabuk (En Temel):**
     * `init=/bin/bash` (veya `/bin/sh`): Init sistemini tamamen atlar ve doğrudan bir root kabuğu başlatır. Kök dosya sistemi genellikle salt okunur olarak bağlanır ve diğer dosya sistemleri bağlanmaz. Çok temel kurtarma işlemleri için kullanılır.
4. **Sistemi Başlatma:** Parametreyi ekledikten sonra, sistemi bu parametrelerle başlatmak için belirtilen tuş kombinasyonuna basın (GRUB'da genellikle `Ctrl+X` veya `F10`).

## Kurtarma Modunda Çalışma

* **Root Kabuğu:** Genellikle doğrudan bir root kabuğu (#) açılır veya root şifresi istenir.
* **Dosya Sistemi Erişimi:**
  * `rescue.target` modunda dosya sistemleri genellikle okunur-yazılır (`rw`) olarak bağlanır.
  * `emergency.target` veya `init=/bin/bash` modlarında kök dosya sistemi genellikle salt okunur (`ro`) olarak bağlanır. Dosyalarda değişiklik yapmak için önce okunur-yazılır olarak yeniden bağlamanız gerekir:

    ```bash
    mount -o remount,rw /
    ```
  * Diğer dosya sistemlerini (`/home`, `/var` vb.) manuel olarak bağlamanız gerekebilir:

    ```bash
    mount /home
    mount -a # /etc/fstab içindeki diğerlerini bağlamayı dener
    ```
* **Ağ:** `rescue.target` ve `emergency.target` modlarında ağ genellikle aktif değildir. Gerekirse manuel olarak yapılandırıp başlatmanız gerekebilir.
* **Yapılacak İşlemler:** Gerekli bakım veya onarım işlemlerini yapın (şifre sıfırlama, `fsck`, yapılandırma dosyası düzenleme vb.).

## Kurtarma Modundan Çıkma

İşlemlerinizi tamamladıktan sonra:

* Eğer `init=/bin/bash` kullandıysanız, sistemi güvenli bir şekilde yeniden başlatmak zordur. Genellikle `sync` komutunu çalıştırıp ardından `reboot -f` (zorla yeniden başlatma) veya makineyi fiziksel olarak resetlemek gerekebilir.
* `rescue.target` veya `emergency.target` modlarında (veya SysVinit runlevel 1'de), genellikle `exit` yazarak veya `Ctrl+D` tuşlarına basarak normal başlatma sürecine devam edebilir veya `reboot` ya da `systemctl reboot` komutuyla sistemi yeniden başlatabilirsiniz.

Tek kullanıcı modu ve diğer kurtarma modları, sistem yöneticileri için önemli sorun giderme araçlarıdır.


# BASH Programlama

GNU/Linux üzerinde bugün en yaygın kullanılan kabuğun **bash** (Bourne Again SHell) olduğunu söyleyebiliriz. Bu bölümde bash kullanarak akıllı işlemleri nasıl yapacağımızı, temel kontrolleri, hatta basit bazı yükleme scriptleri geliştirmeyi göreceğiz.

## Temel Kontroller

Bash scriptlerinin temel yapısı, başında yorumlayıcının belirtildiği, ardından gerekli komutların sıralandığı dosyalardır. Aşağıdaki scripti `yukle.sh` ismiyle kaydedip çalıştıralım.

```bash
#!/bin/bash
# yukle.sh dosya icerigi

echo "Yukleme basliyor..."
```

```bash
eaydin@dixon ~/calisma/bash $ chmod +x yukle.sh 
eaydin@dixon ~/calisma/bash $ ./yukle.sh
Yukleme basliyor...
```

Tabii scriptimiz bu haliyle pek işe yaramıyor. Örneğin **htop** programının yüklenmesini sağlayabiliriz.

```bash
eaydin@dixon ~/calisma/bash $ cat yukle.sh 
#!/bin/bash
# yukle.sh dosya icerigi

echo "Yukleme basliyor..."
apt-get install htop
```

```bash
eaydin@dixon ~/calisma/bash $ ./yukle.sh 
Yukleme basliyor...
E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)
E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?
```

Gördüğünüz gibi, apt-get programı **root** yetkimiz olmadığı için hata verdi. root yetkimizin olup olmadığının kontrolünü scriptimize yaptırıp buna uygun bir hata verebilirdik.

```bash
eaydin@dixon ~/calisma/bash $ cat yukle.sh 
#!/bin/bash
# yukle.sh dosya icerigi

# Root yetkisi kontrolü (Modern Yöntem: $EUID)
if [[ "$EUID" -ne 0 ]]; then
    echo "Hata: Bu betik root yetkisi ile çalıştırılmalıdır." >&2 # Hata mesajını stderr'e yaz
    exit 1
fi

echo "Yükleme başlıyor..."
# Modern Debian/Ubuntu paket yöneticisi: apt
apt install -y htop # -y ile onayı otomatik ver

# Betiğin başarıyla tamamlandığını belirt
exit 0
```

```bash
eaydin@dixon ~/calisma/bash $ ./yukle.sh 
Hata: Bu betik root yetkisi ile çalıştırılmalıdır.
```

Yukarıdaki satırların üzerinden geçecek olursak:

* `[[ "$EUID" -ne 0 ]]`: Betiği çalıştıran kullanıcının etkili kullanıcı kimliğinin (Effective User ID) 0 (yani root) olup olmadığını kontrol eder. `[[ ... ]]` modern Bash test yapısıdır. `$EUID` değişkeni genellikle `$(id -u)`'dan daha pratiktir.
* `>&2`: Hata mesajlarının standart çıktı (stdout) yerine standart hataya (stderr) yönlendirilmesi iyi bir pratiktir.
* `exit 1`: Betiğin bir hata koduyla (genellikle 0 olmayan bir değer) sonlanmasını sağlar.
* `apt install -y htop`: `apt-get` yerine modern `apt` komutu kullanılır. `-y` seçeneği, kurulum sırasında sorulacak onay sorularına otomatik olarak "evet" yanıtı verir.
* `exit 0`: Betiğin başarıyla tamamlandığını belirtir.

Yukarıdaki programın nasıl sonuçlandığını (exit mesajını) almak için aşağıdaki yöntemi kullanabiliriz.

```bash
eaydin@dixon ~/calisma/bash $ echo $?
1
```

Buradaki **$?** bash için özel bir değişkendir ve "bir önceki programın hata mesajı"nı temsil eder. Yani programımız root yetkisiyle çalıştırılmadığı için **exit 1** ile çıkmış.

Şimdi programımızı root yetkisiyle çalıştıralım.

```bash
eaydin@dixon ~/calisma/bash $ sudo ./yukle.sh 
Yukleme basliyor...
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  htop
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/68,0 kB of archives.
After this operation, 188 kB of additional disk space will be used.
Selecting previously unselected package htop.
(Reading database ... 175141 files and directories currently installed.)
Preparing to unpack .../htop_1.0.2-3_amd64.deb ...
Unpacking htop (1.0.2-3) ...
Processing triggers for gnome-menus (3.10.1-0ubuntu2) ...
Processing triggers for desktop-file-utils (0.22-1ubuntu1) ...
Processing triggers for mime-support (3.54ubuntu1.1) ...
Processing triggers for man-db (2.6.7.1-1ubuntu1) ...
Setting up htop (1.0.2-3) ...
```

Programımızı tekrar çalıştırırsak, htop'un zaten yüklü olduğunu göreceğiz. Öyleyse programımız bunu da kontrol etsin.

Bir paketin kurulu olup olmadığını kontrol etmenin daha güvenilir yolu, paket yöneticisinin kendi sorgulama mekanizmasını kullanmaktır. `grep` ile filtrelemek, paket adının başka bir paketin açıklamasında geçmesi gibi durumlarda yanıltıcı olabilir.

* **Debian/Ubuntu:** `dpkg -s <paket_adı>` komutunun çıkış kodunu kontrol edebiliriz. Paket kuruluysa komut 0 ile çıkar, kurulu değilse 0 olmayan bir kodla çıkar.
* **RHEL/CentOS/Fedora:** `rpm -q <paket_adı>` komutunun çıkış kodunu kontrol edebiliriz. Paket kuruluysa 0, değilse 0 olmayan bir kodla çıkar.

```bash
#!/bin/bash
# yukle.sh dosya icerigi

# Root yetkisi kontrolü
if [[ "$EUID" -ne 0 ]]; then
    echo "Hata: Bu betik root yetkisi ile çalıştırılmalıdır." >&2
    exit 1
fi

PACKAGE_NAME="htop"

# htop zaten yuklu mu? (dpkg -s kullanarak)
# Çıktıyı ve hatayı /dev/null'a yönlendir (&>) ve sadece çıkış kodunu kontrol et ($?)
if dpkg -s "$PACKAGE_NAME" &> /dev/null; then
    echo "$PACKAGE_NAME zaten kurulu."
else
    echo "$PACKAGE_NAME kuruluyor..."
    apt install -y "$PACKAGE_NAME"
fi

exit 0
```

## Parametrik Kullanım

Programımız sadece htop için çalışıyor, eğer herhangi bir program için çalışmasını isteseydik, parametre almamız gerekirdi.

Bash ile gelen parametrelerin sayısını **$#** ile, gelen her parametreyi ise **$1 $2 $3 ...** şeklinde alabilirsiniz.

```bash
#!/bin/bash
# yukle.sh dosya icerigi

# Root yetkiniz var mi?
if [ $(id -u) -ne 0 ]; then
    echo "root yetkisi ile calistirilmali"
    exit 1
fi

# Parametre sayisi kontrol ediliyor
# $# değişkeni betiğe verilen argüman sayısını tutar
if [[ "$#" -lt 1 ]]; then
    echo "Hata: Lütfen kurulacak paket adını belirtin." >&2
    echo "Kullanım: $0 <paket_adı>" >&2 # $0 betiğin kendi adını verir
    exit 1
fi

# İlk argümanı bir değişkene ata (daha okunaklı)
PACKAGE_NAME="$1" # Değişkenleri çift tırnak içinde kullanmak önemlidir

# program zaten yuklu mu? (dpkg -s kullanarak)
if dpkg -s "$PACKAGE_NAME" &> /dev/null; then
    echo "$PACKAGE_NAME zaten kurulu."
else
    echo "$PACKAGE_NAME kuruluyor..."
    apt install -y "$PACKAGE_NAME"
fi

exit 0
```

```bash
eaydin@dixon ~/calisma/bash $ sudo ./yukle.sh 
Parametre vermediniz
Kullanım: yukle.sh program-adi
eaydin@dixon ~/calisma/bash $ echo $?
1
eaydin@dixon ~/calisma/bash $ sudo ./yukle.sh htop
htop zaten yuklu
eaydin@dixon ~/calisma/bash $ sudo ./yukle.sh atop
Yukleme basliyor...
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  atop
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/102 kB of archives.
After this operation, 281 kB of additional disk space will be used.
Selecting previously unselected package atop.
(Reading database ... 175134 files and directories currently installed.)
Preparing to unpack .../archives/atop_1.26-2_amd64.deb ...
Unpacking atop (1.26-2) ...
Processing triggers for man-db (2.6.7.1-1ubuntu1) ...
Processing triggers for ureadahead (0.100.0-16) ...
Setting up atop (1.26-2) ...
Processing triggers for ureadahead (0.100.0-16) ...
```

## Dosyanın Var Olup Olmadığını Anlama

Programımız fena iş çıkarmasa da, sadece Debian sistemler üzerinde çalışacak şekilde yazıldı, ve bunun kontrolünü hiç yapmıyor. Öte yandan sistemimizin Debian olup olmadığını anlamak için `/etc/debian_version` dosyasının var olup olmadığına bakmamız yeterli. Bunun için bash aşağıdaki gibi bir kontrol mekanizması sunuyor.

```bash
if [ -f /etc/debian_version ]; then
    echo "Bu sistem bir Debian türevi"
fi
```

Veya aşağıdaki yöntemle bir dosyanın var olmadığını kontrol edebilirdik.

```bash
if [ ! -f /etc/redhat-release ]; then
    echo "Bu sistem bir Red Hat türevi değil"
fi
```

Bu kontrolleri kullanarak, sistem Debian ise dpkg ve apt-get komutlarını, Red Hat ise rpm ve yum komutlarını kullanabiliriz. Scriptimizin son hali aşağıdaki gibi.

```bash
eaydin@dixon ~/calisma/bash $ cat yukle.sh 
#!/bin/bash
# yukle.sh dosya icerigi

# Root yetkiniz var mi?
if [ $(id -u) -ne 0 ]; then
    echo "root yetkisi ile calistirilmali"
    exit 1
fi

# Parametre sayisi kontrol ediliyor
if [ $# -lt 1 ]; then
    echo "Parametre vermediniz"
    echo "Kullanım: yukle.sh program-adi"
    exit 1
fi

# Eger sistem Debian/Ubuntu ise
if [[ -f /etc/debian_version ]]; then
    echo "Debian/Ubuntu tabanlı sistem algılandı."
    # program zaten yuklu mu?
    if dpkg -s "$PACKAGE_NAME" &> /dev/null; then
        echo "$PACKAGE_NAME zaten kurulu."
    else
         echo "$PACKAGE_NAME kuruluyor (apt)..."
         apt update # Kurulumdan önce listeyi güncellemek iyi bir pratik
         apt install -y "$PACKAGE_NAME"
    fi
# Eger sistem RHEL/CentOS/Fedora ise
elif [[ -f /etc/redhat-release ]]; then
    echo "Red Hat tabanlı sistem algılandı."
    # program zaten yuklu mu?
    if rpm -q "$PACKAGE_NAME" &> /dev/null; then
        echo "$PACKAGE_NAME zaten kurulu."
    else
        echo "$PACKAGE_NAME kuruluyor (dnf)..."
        dnf install -y "$PACKAGE_NAME"
    fi
# Tanımlanamayan sistem
else
    echo "Hata: Desteklenmeyen veya tanımlanamayan Linux dağıtımı." >&2
    exit 1
fi

exit 0
```

(Not: Dağıtımı belirlemek için `/etc/os-release` dosyasını kontrol etmek daha modern bir yöntemdir, ancak bu örnek için dosya varlığı kontrolü yeterlidir.)

## Fonksiyonlar

Yukarıdaki yükleme işlemlerini işletim sistemi özelinde fonksiyonlara taşırsak ileride geliştirmesi daha rahat olabilir.

Fonksiyonlar hakkında karıştırılmaması gereken, argümanları da tıpkı programın kendisi gibi **$1 $2 $3 ...** şeklinde ifade edilir. Dolayısıyla fonksiyon içerisinde kullanacağınız **$1** ifadesi, fonksiyona gönderilen 1. parametre olur, programa gönderilen değil. Fonksiyon içinden, programa gönderilen parametrelere doğrudan erişemezsiniz, ancak dolaylı olarak erişebilirsiniz.

Yükleme işlemimizi fonksiyonlara bölüp programın son halini görelim.

```bash
#!/bin/bash
# yukle.sh dosya icerigi

# Debian/Ubuntu Yukleme Fonksiyonu
debian_yukle() {
    local pkg_name="$1" # Fonksiyon içi yerel değişken kullan
    # program zaten yuklu mu?
    if dpkg -s "$pkg_name" &> /dev/null; then
        echo "$pkg_name zaten kurulu."
    else
         echo "$pkg_name kuruluyor (apt)..."
         apt update 
         apt install -y "$pkg_name"
    fi
    # Fonksiyonun çıkış kodunu apt install'dan al (başarı/hata)
    return $? 
}

# RHEL/CentOS/Fedora Yukleme Fonksiyonu
redhat_yukle() {
    local pkg_name="$1"
    # program zaten yuklu mu?
    if rpm -q "$pkg_name" &> /dev/null; then
        echo "$pkg_name zaten kurulu."
    else
        echo "$pkg_name kuruluyor (dnf)..."
        dnf install -y "$pkg_name"
    fi
    return $?
}

# === Ana Betik Mantığı ===

# Root yetkisi kontrolü
if [[ "$EUID" -ne 0 ]]; then
    echo "Hata: Bu betik root yetkisi ile çalıştırılmalıdır." >&2
    exit 1
fi

# Parametre sayısı kontrolü
if [[ "$#" -lt 1 ]]; then
    echo "Hata: Lütfen kurulacak paket adını belirtin." >&2
    echo "Kullanım: $0 <paket_adı>" >&2
    exit 1
fi

# Kurulacak paketi değişkene ata
PACKAGE_TO_INSTALL="$1"

# Dağıtımı kontrol et ve ilgili fonksiyonu çağır
if [[ -f /etc/debian_version ]]; then
    echo "Debian/Ubuntu tabanlı sistem algılandı."
    debian_yukle "$PACKAGE_TO_INSTALL" # Değişkeni tırnak içinde kullan
    exit_code=$? # Fonksiyonun çıkış kodunu yakala

elif [[ -f /etc/redhat-release ]]; then
    echo "Red Hat tabanlı sistem algılandı."
    redhat_yukle "$PACKAGE_TO_INSTALL" # Değişkeni tırnak içinde kullan
    exit_code=$?

else
    echo "Hata: Desteklenmeyen veya tanımlanamayan Linux dağıtımı." >&2
    exit 1
fi

# Fonksiyonun çıkış koduna göre betiğin çıkış kodunu ayarla
exit $exit_code
```

Bu örnekler, Bash betiklerinin temellerini (değişkenler, koşullar, fonksiyonlar, komut çalıştırma, çıkış kodları) göstermektedir. Daha karmaşık görevler için döngüler, dizi değişkenler, metin işleme gibi konular [Döngüler ve Diğer Kontrol Yöntemleri](/bash-programlama/doengueler-ve-diger-kontrol-yoentemleri) bölümünde ele alınacaktır.


# Döngüler ve Diğer Kontrol Yöntemleri

Bash programlamanın temellerini anladıktan sonra, döngüler ve yaygın kullanılan kontrol yöntemlerini inceleyebiliriz.

## `for` Döngüsü

`for` döngüsü, bir listedeki (kelimeler, dosya adları vb.) her öğe için belirli komutları tekrarlamak amacıyla kullanılır.

**Örnek 1: Dosyalar Üzerinde Döngü (Globbing ile - Önerilen Yöntem)**

Mevcut dizindeki tüm `.txt` dosyalarını listelemek için:

```bash
#!/bin/bash

echo "Bulunan .txt dosyaları:"
# '*' glob karakteri mevcut dizindeki tüm .txt dosyalarıyla eşleşir
# Dosya adlarında boşluk veya özel karakter varsa, tırnak içinde kullanmak önemlidir
for dosya in *.txt; do
    # Dosyanın var olup olmadığını kontrol et (eğer hiç .txt dosyası yoksa glob kendisiyle eşleşir)
    if [[ -f "$dosya" ]]; then 
        echo "İşlenen dosya: $dosya"
    fi
done
```

**Uyarı:** `for i in $(ls)` gibi `ls` komutunun çıktısını ayrıştırmak, dosya adlarında boşluk veya özel karakterler olduğunda sorunlara yol açar ve **kesinlikle önerilmez**. Dosyalar üzerinde işlem yapmak için globbing (`*`, `?`, `[...]`) veya `find` komutu ile `while read` döngüsü kullanılmalıdır.

**Örnek 2: Sayı Aralığında Döngü**

```bash
#!/bin/bash

echo "1'den 5'e kadar sayılar:"
for i in {1..5}; do
    echo "Sayı: $i"
done
```

## `while` Döngüsü

`while` döngüsü, belirli bir koşul doğru (`true`, çıkış kodu 0) olduğu sürece komutları tekrarlar. Koşul genellikle `[[ ... ]]` test ifadesiyle kontrol edilir.

Aşağıda 0'dan 9'a kadar sayan basit bir `while` döngüsü örneği ve modern Bash aritmetik/test sözdizimi gösterilmiştir:

```bash
#!/bin/bash

SAYAC=0
# [[ ... ]] modern test yapısı, -lt sayısal karşılaştırma (less than)
while [[ "$SAYAC" -lt 10 ]]; do
    echo "Sayaç durumu: $SAYAC"
    # ((...)) modern aritmetik yapısı
    ((SAYAC++)) 
    # Alternatifler: ((SAYAC = SAYAC + 1)) veya let SAYAC=SAYAC+1
done
```

```bash
eaydin@dixon ~/calisma/bash $ ./while.sh 
Sayac durumu: 0
Sayac durumu: 1
Sayac durumu: 2
Sayac durumu: 3
Sayac durumu: 4
Sayac durumu: 5
Sayac durumu: 6
Sayac durumu: 7
Sayac durumu: 8
Sayac durumu: 9
```

## `until` Döngüsü

`until` döngüsü, `while`'ın tersidir; belirtilen koşul yanlış (`false`, çıkış kodu 0 olmayan) olduğu sürece komutları tekrarlar. Koşul doğru olduğunda döngü sona erer.

```bash
#!/bin/bash

SAYAC=0
# Sayaç 5'e eşit olana kadar döngü devam eder
until [[ "$SAYAC" -eq 5 ]]; do
    echo "Until Sayaç: $SAYAC"
    ((SAYAC++))
done
```

## `case` İfadesi

Bir değişkenin değerini birden fazla kalıpla karşılaştırmak için `if`/`elif`/`else` yapısına alternatif olarak `case` ifadesi kullanılır. Özellikle menü seçenekleri veya komut satırı argümanlarını işlemek için kullanışlıdır.

Aşağıdaki örnekte `case` kullanımı, `echo -n` (yeni satır eklemeden yazdırma) ve `read -r` (kullanıcıdan güvenli girdi okuma) gösterilmektedir:

```bash
#!/bin/bash

# -n ile yeni satır eklemeden soruyu sor
echo -n "İşleme devam etmek istiyor musunuz? [E/H]: " 
# -r ile ters eğik çizgilerin yorumlanmasını engelle
read -r cevap 

# cevap değişkeninin değerini kontrol et
case "$cevap" in
    # Büyük/küçük E veya e ile başlayanlar
    [Ee]*) 
        echo "İşlem devam ediyor..."
        ;; 
    # Büyük/küçük H veya h ile başlayanlar
    [Hh]*) 
        echo "İşlem iptal edildi."
        ;;
    # Yukarıdaki kalıplara uymayan her şey (*)
    *) 
        echo "Geçersiz seçenek."
        ;;
esac # case ifadesini bitir
```

* Her kalıp `)` ile biter.
* Her kalıp bloğundaki komutlar `;;` ile sonlandırılır.
* `*` kalıbı, diğer kalıpların hiçbiriyle eşleşmeyen durumları yakalar (varsayılan durum gibi).

Örnek Çalıştırma:

```bash
$ ./case.sh 
İşleme devam etmek istiyor musunuz? [E/H]: E
İşlem devam ediyor...

$ ./case.sh
İşleme devam etmek istiyor musunuz? [E/H]: h
İşlem iptal edildi.

$ ./case.sh
İşleme devam etmek istiyor musunuz? [E/H]: Belki
Geçersiz seçenek.
```


# Menüler

Yazdığınız programların kullanıcı ile etkileşimini sağlayan çeşitli menüler oluşturmak isteyebilirsiniz. Aşağıda iki yöntemini sunacağız.

## `select` Komutu

Bash kabuğunun kendi içinde bulunan `select` komutu, kullanıcıya numaralandırılmış bir seçenek listesi sunar ve seçilen öğeye göre işlem yapmanızı sağlar. `for` döngüsüne benzer bir yapısı vardır.

```bash
#!/bin/bash

# Boşluk içeren seçenekler için tırnak kullanmak daha güvenli olabilir
# veya bir dizi (array) kullanılabilir:
# SECENEKLER=("Disk Durumu" Yardım Çıkış)
# select i in "${SECENEKLER[@]}"; do ...
SECENEKLER="Disk-Durumu Yardim Cikis"

# PS3 değişkeni select'in göstereceği istemi (prompt) ayarlar
PS3="Lütfen bir seçenek girin (1-3): " 

echo "Bir işlem seçin:"
select i in $SECENEKLER; do
    # Modern test [[ ... ]] kullanımı
    if [[ "$i" == "Cikis" ]]; then
        echo "Çıkılıyor..."
        break # Döngüden çık
    elif [[ "$i" == "Yardim" ]]; then
        echo "Yardım menüsü gösteriliyor..."
        # Burada yardım metni gösterilebilir
    elif [[ "$i" == "Disk-Durumu" ]]; then
        echo "Disk durumu:"
        df -h
    else
        # Kullanıcı geçersiz bir numara girerse $i boş olur
        # $REPLY değişkeni kullanıcının girdiği ham değeri içerir
        echo "Geçersiz seçenek: $REPLY"
    fi
done
```

Örnek Çalıştırma:

```bash
$ ./select.sh 
Bir işlem seçin:
1) Disk-Durumu
2) Yardim
3) Cikis
Lütfen bir seçenek girin (1-3): 1
Disk durumu:
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3       346G   32G  296G  10% /
udev            3,8G     0  3,8G   0% /dev
tmpfs           777M  1,5M  775M   1% /run
/dev/sda6       374G  150G  225G  40% /media/backups
Lütfen bir seçenek girin (1-3): 4
Geçersiz seçenek: 4
Lütfen bir seçenek girin (1-3): 3
Çıkılıyor...
$ 
```

## `whiptail` (ve `dialog`)

`whiptail`, `newt` kütüphanesini kullanarak terminalde metin tabanlı grafiksel diyalog kutuları (mesaj kutuları, giriş kutuları, menüler vb.) oluşturmanızı sağlayan bir programdır. Kurulum betiklerinde veya basit TUI (Text User Interface) uygulamalarında kullanıcı etkileşimi için sıkça kullanılır.

Benzer bir araç olan `dialog`, `ncurses` kütüphanesini kullanır ve genellikle `whiptail` ile çok benzer komut satırı seçeneklerine sahiptir. Sisteminizde hangisinin kurulu olduğuna bağlı olarak birini tercih edebilirsiniz (`sudo apt install whiptail` veya `sudo apt install dialog` / `sudo dnf install newt` veya `sudo dnf install dialog`).

Aşağıda `whiptail` ile bazı yaygın diyalog kutusu örnekleri verilmiştir.

**Not:** `whiptail` genellikle kullanıcı seçimini veya girdisini standart hataya (stderr - FD 2) yazar. Bunu bir değişkene atamak için, standart hata ile standart çıktının yerini değiştirmek gerekir. Örneklerdeki `3>&1 1>&2 2>&3` ifadesi bu işlemi yapar:

1. `3>&1`: Geçici olarak FD 3'ü orijinal standart çıktıya (FD 1) yönlendirir.
2. `1>&2`: Standart çıktıyı (FD 1) standart hataya (FD 2) yönlendirir (whiptail'in arayüzü buraya gider).
3. `2>&3`: Standart hatayı (FD 2 - whiptail'in çıktısı) orijinal standart çıktıya (artık FD 3'te saklanan) yönlendirir.\
   Bu sayede `$(...)` komut yakalama mekanizması, `whiptail`'in stderr'e yazdığı sonucu yakalayabilir.

### msgbox

Aşağıdaki gibi bir komut ile görsel bir uyarı sağlayabilirsiniz.

```bash
whiptail --title "Bilgi" --msgbox "Bu bir uyarı mesajıdır." 10 50 
```

Komutun sonundaki rakamlar (10 50), pencerenin yüksekliğini (satır) ve genişliğini (karakter) belirtir.

Örneğin **Ok** yerine **Tamam** yazmasını sağlayabilirdik:

```bash
whiptail --msgbox "Bu bir uyarı mesajıdır." 10 50 --ok-button "Tamam"
```

### yes/no

Programınızın basit Evet/Hayır soruları sormasını sağlayabilirsiniz. `whiptail --yesno` komutu, kullanıcı "Evet" seçerse 0, "Hayır" seçerse 1 çıkış koduyla sonlanır. `$?` ile bu kontrol edilebilir.

```bash
#!/bin/bash

if whiptail --title "Anket" --yesno "GNU/Linux'u özgür buluyor musunuz?" \
   --yes-button Evet --no-button Hayır 10 60; then
    whiptail --msgbox "Çok haklısınız!" --ok-button Tamam 10 40
else
    whiptail --msgbox "Yanılıyor olabilirsiniz?" --ok-button Tamam 10 40
fi
```

### inputbox

Kullanıcıdan metin girdisi almak için `inputbox` kullanılır. Girilen metin standart hataya yazdırılır.

```bash
#!/bin/bash

# Mevcut hostname'i al
mevcut_hostname=$(hostname)

# Kullanıcıdan yeni hostname'i iste, sonucu YENI_HOSTNAME değişkenine ata
YENI_HOSTNAME=$(whiptail --inputbox "Yeni Hostname Giriniz:" \ 
8 60 "$mevcut_hostname" --title "Hostname Değiştirme" --ok-button Tamam \
--cancel-button İptal 3>&1 1>&2 2>&3)

# Kullanıcının Tamam mı İptal mi seçtiğini kontrol et ($? çıkış kodudur)
exit_status=$?

# Eğer Tamam seçildiyse (çıkış kodu 0) ve girilen değer boş değilse
if [[ $exit_status -eq 0 ]] && [[ -n "$YENI_HOSTNAME" ]]; then
    echo "Hostname '$YENI_HOSTNAME' olarak değiştiriliyor..."
    # sudo hostnamectl set-hostname "$YENI_HOSTNAME" # Modern systemd yöntemi
    # veya sadece geçici olarak: sudo hostname "$YENI_HOSTNAME"
else
    echo "İşlem iptal edildi veya boş değer girildi."
fi
```

### menu

Kullanıcıya bir listeden tek bir seçim yapma imkanı sunar. Seçilen öğenin "etiketi" standart hataya yazdırılır.

```bash
#!/bin/bash

# Menü seçenekleri: "Etiket" "Açıklama" şeklinde çiftler halinde
SECIM=$(whiptail --title "Programlama Menüsü" \
--menu "Favori dilinizi seçin" 17 60 5 \
"Python" "Guido van Rossum tarafından geliştirildi" \
"C"      "Dennis M. Ritchie tarafından geliştirildi" \
"Perl"   "Larry Wall tarafından geliştirildi" \
"Bash"   "Brian Fox tarafından geliştirildi" \
"Rust"   "Mozilla tarafından geliştirildi" 3>&1 1>&2 2>&3)

exit_status=$?
if [[ $exit_status -eq 0 ]]; then
    echo "Seçtiğiniz dil: $SECIM"
else
    echo "Dil seçmediniz veya iptal ettiniz."
fi
```

### checklist

Kullanıcıya bir listeden birden fazla seçim yapma (işaretleme) imkanı sunar. Seçilen öğelerin etiketleri, tırnak içinde ve boşlukla ayrılarak standart hataya yazdırılır.

```bash
#!/bin/bash

# Menü seçenekleri: "Etiket" "Açıklama" "ON/OFF" (başlangıç durumu)
SECIMLER=$(whiptail --title "Programlama Menüsü" --checklist \
"Kullandığınız Dilleri Seçin (Boşluk ile işaretleyin)" 15 60 5 \
"Python" "Guido van Rossum" ON \
"C"      "Dennis M. Ritchie" OFF \
"Perl"   "Larry Wall" OFF \
"Bash"   "Brian Fox" ON \
"Java"   "James Gosling" OFF 3>&1 1>&2 2>&3)

exit_status=$?
if [[ $exit_status -eq 0 ]]; then
    echo "Seçtiğiniz diller: $SECIMLER"
else
    echo "Dil seçmediniz veya iptal ettiniz."
fi
```

### radiolist

`checklist`'e benzer, ancak kullanıcıya listeden sadece *bir* tane seçim yapma imkanı sunar. Seçilen öğenin etiketi standart hataya yazdırılır.

```bash
#!/bin/bash

# Menü seçenekleri: "Etiket" "Açıklama" "ON/OFF" (sadece biri ON olabilir)
SECIM=$(whiptail --title "Programlama Menüsü" --radiolist \
"En çok kullandığınız dili seçin" 15 60 5 \
"Python" "Guido van Rossum" OFF \
"C"      "Dennis M. Ritchie" ON \
"Perl"   "Larry Wall" OFF \
"Bash"   "Brian Fox" OFF \
"Go"     "Google" OFF 3>&1 1>&2 2>&3)

exit_status=$?
if [[ $exit_status -eq 0 ]]; then
    echo "En çok kullandığınız dil: $SECIM"
else
    echo "Dil seçmediniz veya iptal ettiniz."
fi
```


# Log Dosyaları

Log dosyaları (günlük kayıtları), Linux ve Unix benzeri sistemlerin işleyişini anlamak, sorunları teşhis etmek ve güvenlik olaylarını takip etmek için hayati öneme sahip bilgiler içerir. Sistemde çalışan servisler, çekirdek ve uygulamalar, önemli olayları, uyarıları ve hataları bu dosyalara kaydeder.

## Modern Günlükleme: `systemd-journald`

Modern Linux dağıtımlarının çoğu, `systemd` init sistemi ile birlikte gelen **`systemd-journald`** servisini merkezi günlükleme sistemi olarak kullanır. `journald`, günlükleri yapılandırılmış, indekslenmiş bir ikili (binary) formatta toplar ve saklar.

**`journald`'nin Avantajları:**

* **Merkezi Toplama:** Çekirdek (`kmsg`), servislerin standart çıktı/hataları (stdout/stderr), syslog ve diğer kaynaklardan gelen logları tek bir yerde toplar.
* **Yapılandırılmış Veri:** Loglar sadece metin değil, aynı zamanda PID, UID, GID, servis adı (unit), önyükleme ID'si gibi meta verilerle birlikte saklanır. Bu, filtrelemeyi ve analizi kolaylaştırır.
* **İndeksleme:** Hızlı arama ve filtreleme imkanı sunar.
* **Depolama:** Günlükler genellikle `/var/log/journal/` (kalıcı depolama etkinse) veya `/run/log/journal/` (geçici, sadece mevcut önyükleme için) altında saklanır. Depolama boyutu ve süresi yapılandırılabilir.

**`journalctl` Komutu:**`journald` tarafından toplanan günlüklere erişmek ve sorgulamak için `journalctl` komutu kullanılır:

```bash
# Tüm günlükleri göster (en yeniden en eskiye, less ile sayfalanmış)
journalctl

# Sadece mevcut önyüklemedeki günlükleri göster
journalctl -b

# Sadece çekirdek mesajlarını göster (dmesg gibi)
journalctl -k

# Belirli bir servisin (unit) günlüklerini göster
journalctl -u sshd.service

# Belirli bir PID'ye ait günlükleri göster
journalctl _PID=1234

# Belirli bir zaman aralığındaki günlükleri göster
journalctl --since "yesterday"
journalctl --since "2023-10-26 10:00:00" --until "2023-10-26 11:00:00"

# Günlükleri canlı olarak takip et (-f: follow)
journalctl -f

# Hata (error) seviyesindeki ve daha kritik günlükleri göster (-p: priority)
journalctl -p err 
# Seviyeler: emerg (0), alert (1), crit (2), err (3), warning (4), notice (5), info (6), debug (7)

# Daha fazla örnek ve filtreleme seçeneği için: man journalctl
```

## Geleneksel Günlükleme: `syslog` ve `/var/log`

`journald`'nin yaygınlaşmasından önce, Linux sistemleri logları toplamak ve yönetmek için **syslog** protokolünü ve `syslogd`, `rsyslog`, `syslog-ng` gibi daemon'ları kullanırdı. Bu daemon'lar, farklı kaynaklardan gelen log mesajlarını alır, filtreler ve genellikle `/var/log/` dizini altındaki çeşitli metin dosyalarına yazardı.

Modern sistemlerde bile, `rsyslog` gibi bir syslog daemon'ı genellikle `journald` ile birlikte çalışır. `rsyslog`, `journald`'den logları okuyabilir ve bunları geleneksel `/var/log/` dosyalarına (örn. `/var/log/syslog`, `/var/log/auth.log`, `/var/log/messages`) yazabilir. Bu, eski araçlarla uyumluluk veya logların metin formatında saklanması gerektiğinde kullanışlıdır.

**Syslog Temelleri:**\
Syslog mesajları genellikle iki ana bilgi içerir:

* **Facility (Kaynak):** Mesajı üreten programın türünü belirtir (örn. `kern`, `user`, `mail`, `daemon`, `auth`, `syslog`, `lpr`, `news`, `cron`, `local0` - `local7`).
* **Severity/Priority (Önem Derecesi):** Mesajın önemini belirtir (yukarıda `journalctl -p` kısmında listelenmiştir: `emerg`, `alert`, `crit`, `err`, `warning`, `notice`, `info`, `debug`).

`rsyslog` gibi daemon'lar, `/etc/rsyslog.conf` ve `/etc/rsyslog.d/` altındaki dosyalarda tanımlanan kurallara göre, hangi facility/severity kombinasyonuna sahip mesajların hangi dosyaya yazılacağını veya nereye (örn. uzak sunucu) gönderileceğini belirler.

**Yaygın Geleneksel Log Dosyaları (`/var/log/` altında):**

* `/var/log/messages` veya `/var/log/syslog`: Genel sistem mesajları, birçok servisin varsayılan log hedefi (dağıtıma göre değişir). `journald` sonrası önemi azalmıştır.
* `/var/log/auth.log` veya `/var/log/secure`: Kimlik doğrulama ile ilgili mesajlar (login, sudo, sshd vb.).
* `/var/log/kern.log`: Çekirdek mesajları.
* `/var/log/dmesg`: Sistem başlangıcındaki çekirdek halka arabelleği (ring buffer) mesajları. `dmesg` komutu ile de okunabilir.
* `/var/log/boot.log`: Sistem başlangıç süreciyle ilgili mesajlar.
* `/var/log/cron` veya `/var/log/syslog`: Zamanlanmış görev (cron) logları.
* `/var/log/maillog` veya `/var/log/mail.log`: Posta sunucusu logları.
* `/var/log/httpd/` veya `/var/log/apache2/`: Apache web sunucusu logları (`access_log`, `error_log`).
* `/var/log/nginx/`: Nginx web sunucusu logları.
* `/var/log/mysql/` veya `/var/log/mariadb/`: Veritabanı sunucusu logları.

Bu dosyalar genellikle düz metin formatındadır ve `cat`, `less`, `tail`, `grep`, `awk`, `sed` gibi standart araçlarla incelenebilir. `tail -f <dosya>` komutu, bir log dosyasını canlı olarak takip etmek için sıkça kullanılır.

## Log Rotasyonu (`logrotate`)

Log dosyaları zamanla çok büyüyebilir ve disk alanını doldurabilir. `logrotate` aracı, log dosyalarını düzenli aralıklarla (günlük, haftalık, aylık) otomatik olarak arşivlemek, sıkıştırmak ve eskiyenleri silmek için kullanılır.

* **Yapılandırma:** Ana yapılandırma dosyası `/etc/logrotate.conf`'tur. Uygulamaya özel kurallar ise genellikle `/etc/logrotate.d/` dizini altındaki dosyalarda tanımlanır.
* **Çalışma:** `logrotate` genellikle bir cron işi tarafından (örn. `/etc/cron.daily/logrotate`) günde bir kez çalıştırılır.
* **Örnek Yapılandırma (`/etc/logrotate.d/apache2`):**

  ```
  /var/log/apache2/*.log {
      daily          # Günlük olarak rotate et
      missingok      # Log dosyası yoksa hata verme
      rotate 14      # 14 gün boyunca eski logları sakla
      compress       # Eski logları gzip ile sıkıştır
      delaycompress  # Bir sonraki rotasyonda sıkıştır (servisin yeniden başlatılmasına zaman tanır)
      notifempty     # Log dosyası boşsa rotate etme
      create 640 root adm # Yeni log dosyasını belirtilen izin/sahip/grup ile oluştur
      sharedscripts  # postrotate/prerotate betiklerini tüm loglar için bir kez çalıştır
      postrotate
          # Apache'yi yeniden yükle (logları tekrar açması için)
          if /etc/init.d/apache2 status > /dev/null ; then \
              /etc/init.d/apache2 reload > /dev/null; \
          fi;
          # veya systemd için: systemctl reload apache2.service
      endscript
      prerotate
          # Rotasyondan önce yapılacaklar (varsa)
      endscript
  }
  ```
* **Test Etme:** Bir yapılandırma dosyasının nasıl çalışacağını test etmek için `-d` (debug) seçeneği kullanılır:

  ```bash
  sudo logrotate -d /etc/logrotate.d/apache2
  ```
* **Zorla Çalıştırma:** Rotasyonu hemen tetiklemek için `-f` (force) seçeneği kullanılır:

  ```bash
  sudo logrotate -f /etc/logrotate.conf
  ```

Etkili log yönetimi, hem `journald`'nin modern yeteneklerini hem de `logrotate` gibi geleneksel araçları anlamayı gerektirir.

## Uygulama Logları ve Özel Rotasyon

Sistem loglarının yanı sıra, çalıştırdığınız uygulamaların (web sunucuları, veritabanları, özel uygulamalar vb.) kendi log dosyaları olacaktır. Bu logların konumları uygulamaya göre değişir, ancak genellikle `/var/log/` altında kendi alt dizinlerinde (örn. `/var/log/nginx/`) veya uygulamanın kendi dizininde bulunurlar.

Web hosting gibi ortamlarda, her kullanıcı veya sanal ana bilgisayar (virtual host) için ayrı log dosyaları tutmak yaygındır. Bu loglar genellikle kullanıcının ev dizini altında özel bir `logs` klasöründe saklanabilir (örn. `/home/kullanici_adi/logs/`).

Bu özel log dosyalarının da düzenli olarak rotate edilmesi gerekir. `logrotate` bunun için de kullanılabilir. `/etc/logrotate.d/` altına özel bir yapılandırma dosyası ekleyerek bu logları yönetebilirsiniz.

**Örnek: Kullanıcı Loglarını Rotate Etme (`/etc/logrotate.d/virtualhosts`)**

Aşağıdaki örnek, `/home/` altındaki tüm kullanıcıların `logs` dizinlerindeki `.log` uzantılı dosyaları günlük olarak rotate eder, 7 gün saklar ve sıkıştırır:

```
/home/*/logs/*.log {
    daily          # Günlük rotate et
    rotate 7       # 7 eski log dosyası sakla
    missingok      # Log dosyası yoksa hata verme
    compress       # Sıkıştır
    delaycompress  # Bir sonraki rotasyonda sıkıştır
    notifempty     # Boşsa rotate etme
    create 0640 kullanici_grubu www-data # Yeni log dosyasını uygun izin/sahip/grup ile oluştur (kullanici_grubu yerine uygun grup adı yazılmalı)
    sharedscripts  # Betikleri bir kez çalıştır
    postrotate
        # İlgili servise logları yeniden açması için sinyal gönder (gerekirse)
        # Örneğin Apache için:
        # if systemctl is-active apache2.service > /dev/null ; then
        #    systemctl reload apache2.service > /dev/null
        # fi
    endscript
}
```

Bu yapılandırmayı test etmek için `sudo logrotate -d /etc/logrotate.d/virtualhosts` komutunu kullanabilirsiniz. Uygulamanızın log dosyalarını doğru şekilde yeniden açması için `postrotate` betiğini uygun şekilde ayarlamak önemlidir.


# Log İnceleme ve Filtreleme

Log dosyaları, sistemin işleyişi hakkında değerli bilgiler içerir, ancak genellikle çok büyük olabilirler. İhtiyaç duyulan bilgiyi bulmak için logları etkili bir şekilde incelemek ve filtrelemek önemlidir. Bu bölümde, hem geleneksel metin tabanlı log dosyaları hem de `journald` günlükleri için yaygın kullanılan araçlar ve teknikler ele alınacaktır.

## Geleneksel Log Dosyaları (`/var/log`)

Bu dosyalar genellikle düz metin formatındadır ve standart komut satırı araçlarıyla işlenebilir.

**1. Canlı Takip ve Basit Filtreleme (`tail -f | grep`)**

Bir log dosyasını gerçek zamanlı olarak takip etmek ve belirli anahtar kelimeleri içeren satırları anında görmek için `tail -f` ve `grep` kombinasyonu sıkça kullanılır:

```bash
# /var/log/syslog dosyasını takip et ve içinde "error" geçen satırları göster (büyük/küçük harf duyarsız)
tail -f /var/log/syslog | grep -i "error"

# /var/log/nginx/access.log dosyasını takip et ve 404 hata kodlarını içeren satırları göster
tail -f /var/log/nginx/access.log | grep ' 404 ' 
```

* `tail -f`: Dosyanın sonunu gösterir ve yeni eklenen satırları sürekli olarak ekrana basar.
* `grep`: Standart girdiden gelen satırlar içinde belirtilen kalıbı arar.

**2. Regex ile Gelişmiş Filtreleme (`grep -E`)**

Daha karmaşık kalıpları eşleştirmek için `grep -E` (veya `egrep`) ile düzenli ifadeler (regular expressions) kullanılır:

```bash
# Apache access_log dosyasında belirli bir IP adresinden gelen istekleri bul
grep -E '^192\.168\.1\.10 ' /var/log/apache2/access.log

# auth.log dosyasında başarısız SSH login denemelerini bul
grep -E 'sshd\[[0-9]+\]: Failed password for' /var/log/auth.log

# access_log dosyasından sadece GET isteklerini içeren satırları çıkar
grep -E '^(\S+) (\S+) (\S+) \[.*\] "GET ' /var/log/nginx/access.log
```

**3. Alanlara Göre İşleme (`awk`)**

Log satırları genellikle boşluk veya başka bir ayırıcı ile ayrılmış alanlardan oluşur. `awk`, bu alanlara göre işlem yapmak için çok güçlü bir araçtır:

```bash
# access_log dosyasındaki her satırın ilk alanını (IP adresi) yazdır
tail -n 50 /var/log/nginx/access.log | awk '{print $1}'

# Belirli bir IP adresinden gelen isteklerin sayısını bul
awk '$1 == "192.168.1.10" { count++ } END { print count }' /var/log/nginx/access.log

# 404 hatası veren isteklerin URL'lerini (7. alan) yazdır
awk '$9 == "404" { print $7 }' /var/log/nginx/access.log | head
```

**4. Metin Değiştirme (`sed`)**

Loglar üzerinde basit metin değiştirme veya ayıklama işlemleri için `sed` kullanılabilir:

```bash
# syslog dosyasındaki tüm "WARN" kelimelerini "UYARI" ile değiştir (sadece ekrana basar)
sed 's/WARN/UYARI/g' /var/log/syslog | less

# access_log dosyasından tarih/saat bilgisini çıkar
sed -E 's/^([^ ]+) ([^ ]+) ([^ ]+) \[.*\] (.*)/\1 \4/' /var/log/nginx/access.log | head
```

## `systemd-journald` Günlükleri (`journalctl`)

`journald`, logları yapılandırılmış bir formatta sakladığı için `journalctl` komutu güçlü filtreleme yetenekleri sunar.

**Canlı Takip:**

```bash
# Tüm günlükleri canlı takip et
sudo journalctl -f

# Belirli bir servisin günlüklerini canlı takip et
sudo journalctl -f -u nginx.service
```

**Filtreleme:**

* **Servise Göre (`-u`):**

  ```bash
  sudo journalctl -u sshd.service
  ```
* **Önem Derecesine Göre (`-p`):**

  ```bash
  # Sadece hata ve daha kritik mesajları göster
  sudo journalctl -p err 

  # Uyarı ve daha kritik mesajları göster
  sudo journalctl -p warning..alert 
  ```
* **Zamana Göre (`--since`, `--until`):**

  ```bash
  sudo journalctl --since "1 hour ago"
  sudo journalctl --since "09:00" --until "10:30"
  ```
* **Çekirdek Mesajları (`-k`):**

  ```bash
  sudo journalctl -k
  ```
* **Belirli Önyükleme (`-b`):**

  ```bash
  sudo journalctl -b    # Mevcut önyükleme
  sudo journalctl -b -1 # Bir önceki önyükleme
  sudo journalctl --list-boots # Tüm önyüklemeleri listele
  ```
* **Meta Veri Alanlarına Göre:** `journald` logları birçok meta veri alanı ile saklar (`_PID`, `_UID`, `_EXE`, `_SYSTEMD_UNIT`, `SYSLOG_FACILITY` vb.). Bu alanlara göre filtreleme yapılabilir:

  ```bash
  # Belirli bir PID'ye ait loglar
  sudo journalctl _PID=12345

  # Belirli bir çalıştırılabilir dosyaya ait loglar
  sudo journalctl /usr/sbin/sshd

  # Belirli bir syslog facility koduna ait loglar
  sudo journalctl SYSLOG_FACILITY=10 # authpriv için
  ```
* **Metin Arama (`grep` ile):** `journalctl` çıktısı metin tabanlı olduğu için `grep` ile de filtrelenebilir:

  ```bash
  sudo journalctl -u nginx.service | grep "denied"
  ```

Logları etkili bir şekilde incelemek, sistem yönetimi ve sorun gidermenin önemli bir parçasıdır. Hem geleneksel araçları hem de `journalctl`'i bilmek, farklı durumlarla başa çıkmanıza yardımcı olur.


# İnternet Servisleri

GNU/Linux işletim sistemleri, esnek ve güçlü yapısı sayesinde çeşitli internet servislerini (ağ hizmetlerini) sunmak için yaygın olarak kullanılır. Bu servisler, basit bir Raspberry Pi'den güçlü sunucu kümelerine kadar farklı donanımlar üzerinde çalışabilir. Bu bölümde, en sık kullanılan internet servislerinden bazıları ve temel kavramları ele alınacaktır.

En yaygın servisler arasında Web (HTTP/HTTPS), E-posta (SMTP/POP3/IMAP), Alan Adı Sistemi (DNS) ve Zaman Senkronizasyonu (NTP) bulunur. Güvenli iletişim için **HTTPS** kullanımı artık standart hale gelmiştir ve şifrelenmemiş HTTP'den **kaçınılmalıdır**.

Aşağıdaki tabloda sıkça kullanılan bazı servisler, varsayılan portları ve temel işlevleri özetlenmiştir:

| Servis     | Protokol/Port     | Açıklama                                                            | Yaygın Yazılımlar             |
| ---------- | ----------------- | ------------------------------------------------------------------- | ----------------------------- |
| HTTP       | TCP(80)           | Web içeriği sunma (şifrelenmemiş)                                   | Apache, Nginx                 |
| HTTPS      | TCP(443)          | Web içeriği sunma (TLS/SSL ile şifrelenmiş)                         | Apache, Nginx                 |
| DNS        | UDP(53), TCP(53)  | Alan adı - IP adresi çözümlemesi                                    | BIND, Unbound, Knot, PowerDNS |
| NTP        | UDP(123)          | Ağ Zaman Protokolü (Zaman senkronizasyonu)                          | ntpd, chronyd                 |
| SMTP       | TCP(25, 587, 465) | E-posta Gönderme (Simple Mail Transfer Protocol)                    | Postfix, Exim, Sendmail       |
| POP3       | TCP(110, 995)     | E-posta Alma (Post Office Protocol v3)                              | Dovecot, Courier              |
| IMAP       | TCP(143, 993)     | E-posta Alma/Yönetme (Internet Message Access Protocol)             | Dovecot, Courier              |
| FTP        | TCP(21, 20)       | Dosya Transfer Protokolü (şifrelenmemiş)                            | vsftpd, ProFTPD               |
| FTPS       | TCP(21, 990, 989) | TLS/SSL üzerinden FTP (şifrelenmiş)                                 | vsftpd, ProFTPD               |
| SFTP (SSH) | TCP(22)           | SSH Dosya Transfer Protokolü (SSH üzerinden, FTP ile ilgisi yoktur) | OpenSSH sshd                  |

Bir web sitesi sunmak için genellikle bir web sunucusuna (Apache veya Nginx gibi) ve dinamik içerik için PHP-FPM gibi bir uygulama sunucusuna ihtiyaç duyulur. DNS ve E-posta gibi hizmetler harici servis sağlayıcılardan alınabilir veya kendi sunucunuzda kurulabilir. Web sitenizden e-posta gönderimi gerekiyorsa, basit bir Mail Transfer Agent (MTA) kurmak (örn. Postfix'in sadece gönderme yapacak şekilde yapılandırılması) veya doğrudan harici bir SMTP sunucusu üzerinden göndermek (daha yaygın ve önerilen) gerekebilir.

Kendi DNS sunucunuzu çalıştırmak, alan adınız için nameserver kayıtlarını (NS) alan adı kayıt firmanız (registrar) üzerinden doğru şekilde yapılandırmanızı ve sunucunuzun ilgili alan adı için yetkili (authoritative) olmasını gerektirir.

**Bu Bölümdeki Konular:**

* [Bir Sayfanın İnternetteki Serüveni](/internet-servisleri/bir-sayfanin-internetteki-serueveni): Bir web sayfasına erişim sürecinin (DNS, HTTP vb.) genel akışı.
* [Nameserver (DNS) Servisleri](/internet-servisleri/nameserver-servisleri): DNS'in çalışma mantığı ve temel kavramlar.
* [Apache Web Sunucusu](/internet-servisleri/apache): Apache'nin kurulumu ve temel yapılandırması.
* [PHP-FPM](/internet-servisleri/php-fpm): PHP betiklerini Apache veya Nginx ile çalıştırmak için PHP-FPM kullanımı.
* [FTP Servisleri](/internet-servisleri/ftp): FTP, FTPS ve SFTP protokolleri ve sunucuları (vsftpd, ProFTPD).


# Bir sayfanın İnternetteki Serüveni

Vermiş olduğumuz eğitimlerde, çoğunlukla İnternet'in çalışma mantığının çok iyi anlatılmadığı ya da kavranmadığı konusunda deneyimlerimiz tecrübe ile sabittir.

Günümüzde internetin temel taşlarından biri Alan Adı Sistemi'dir (DNS - Domain Name System). Bu sistem, insanların kolayca hatırlayabileceği alan adlarını (örn. `www.veriteknik.com.tr`) makinelerin anladığı IP adreslerine (örn. `94.103.33.130`) çevirir. Bu çeviri işleminin en üst seviyesinde **kök DNS sunucuları (root name servers)** bulunur. Bu sunucuların listesi, internetin düzgün çalışması için kritik öneme sahiptir ve genellikle işletim sistemleri veya DNS çözümleyiciler tarafından bilinir. Bu sistemin koordinasyonu ICANN (Internet Corporation for Assigned Names and Numbers) gibi kuruluşlar tarafından yapılır.

Linux sistemlerde, sistemin bildiği kök sunucuları `dig` komutu ile sorgulayabiliriz:

```bash
dig +nocomments
```

```bash
; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.37.rc1.el6_7.4 <<>> +nocomments
;; global options: +cmd
;.                IN    NS
.            277813    IN    NS    a.root-servers.net.
.            277813    IN    NS    g.root-servers.net.
.            277813    IN    NS    c.root-servers.net.
.            277813    IN    NS    l.root-servers.net.
.            277813    IN    NS    m.root-servers.net.
.            277813    IN    NS    f.root-servers.net.
.            277813    IN    NS    i.root-servers.net.
.            277813    IN    NS    b.root-servers.net.
.            277813    IN    NS    j.root-servers.net.
.            277813    IN    NS    d.root-servers.net.
.            277813    IN    NS    h.root-servers.net.
.            277813    IN    NS    e.root-servers.net.
.            277813    IN    NS    k.root-servers.net.
a.root-servers.net.    364471    IN    A    198.41.0.4
a.root-servers.net.    364471    IN    AAAA    2001:503:ba3e::2:30
b.root-servers.net.    364471    IN    A    192.228.79.201
b.root-servers.net.    364471    IN    AAAA    2001:500:84::b
c.root-servers.net.    364471    IN    A    192.33.4.12
c.root-servers.net.    364471    IN    AAAA    2001:500:2::c
d.root-servers.net.    364471    IN    A    199.7.91.13
d.root-servers.net.    364471    IN    AAAA    2001:500:2d::d
e.root-servers.net.    364471    IN    A    192.203.230.10
f.root-servers.net.    364471    IN    A    192.5.5.241
f.root-servers.net.    364471    IN    AAAA    2001:500:2f::f
g.root-servers.net.    364471    IN    A    192.112.36.4
h.root-servers.net.    364471    IN    A    198.97.190.53
;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sat Dec 19 18:22:40 2015
;; MSG SIZE  rcvd: 496
```

Aynı kök sunucu bilgileri genellikle `/etc/named.root` veya benzeri bir dosyada da bulunabilir (BIND gibi DNS sunucu yazılımları tarafından kullanılır). Teorik olarak bu kök sunucuları değiştirmek mümkün olsa da, bu internetin genel işleyişinden kopmak anlamına gelir.

**DNS Çözümleme Adımları:**

Bir web tarayıcısına `https://www.example.com` gibi bir adres yazdığınızda, IP adresini bulmak için genellikle şu adımlar izlenir (bu süreç genellikle `dns_query.png` benzeri bir diagramda gösterilir):

1. **Yerel Önbellek (Cache):** Tarayıcı ve işletim sistemi önce kendi önbelleklerine bakar, adres daha önce çözümlenmiş mi diye kontrol eder.
2. **Hosts Dosyası:** İşletim sistemi `/etc/hosts` dosyasına bakar.
3. **Yerel DNS Sunucusu (Recursive Resolver):** Eğer adres bulunamazsa, istek işletim sisteminin yapılandırıldığı DNS sunucusuna (genellikle internet servis sağlayıcınızın veya Google'ın `8.8.8.8` gibi genel bir sunucusu) iletilir. Bu sunucu "recursive resolver" olarak görev yapar.
4. **Kök Sunucular:** Yerel DNS sunucusu adresi bilmiyorsa, kök DNS sunucularından birine sorar (".com" alan adından sorumlu sunucunun adresini öğrenir).
5. **TLD Sunucuları:** Yerel DNS sunucusu, kök sunucudan aldığı bilgiyle ".com" TLD (Top-Level Domain) sunucusuna sorar ("example.com" alan adından sorumlu sunucunun adresini öğrenir).
6. **Yetkili (Authoritative) Sunucu:** Yerel DNS sunucusu, TLD sunucusundan aldığı bilgiyle "example.com" alan adının yetkili nameserver'ına sorar ("[www.example.com](http://www.example.com)" adresinin IP'sini öğrenir).
7. **Yanıt:** Yetkili sunucu IP adresini yerel DNS sunucusuna bildirir.
8. **Önbelleğe Alma ve İletme:** Yerel DNS sunucusu aldığı IP adresini kendi önbelleğine kaydeder (belirli bir süre için - TTL) ve tarayıcıya/işletim sistemine iletir.

**Not:** DNS sorgularının gizliliğini ve güvenliğini artırmak için DNS over HTTPS (DoH) ve DNS over TLS (DoT) gibi modern protokoller geliştirilmiştir.

**HTTP/HTTPS İsteği:**

Tarayıcı, alan adının IP adresini öğrendikten sonra web sunucusuna bağlanır:

1. **TCP Bağlantısı:** Tarayıcı, hedef IP adresine standart port üzerinden bir TCP bağlantısı başlatır.
   * **HTTPS (Güvenli - Önerilen):** Port 443 kullanılır. Tarayıcı ve sunucu arasında bir **TLS/SSL el sıkışması (handshake)** gerçekleşir. Sunucu sertifikasını sunar, tarayıcı bunu doğrular ve güvenli, şifreli bir kanal oluşturulur.
   * **HTTP (Güvensiz):** Port 80 kullanılır. Bağlantı şifrelenmez.
2. **HTTP İsteği:** Tarayıcı, oluşturulan TCP bağlantısı (veya HTTPS için şifreli TLS kanalı) üzerinden bir HTTP isteği gönderir. Bu istek genellikle şunları içerir:
   * Metot: `GET` (sayfayı isteme), `POST` (veri gönderme) vb.
   * İstenen Kaynak: `/index.html`, `/images/logo.png` vb.
   * HTTP Versiyonu: `HTTP/1.1`, `HTTP/2` vb.
   * Başlıklar (Headers): Tarayıcı tipi (`User-Agent`), kabul edilen içerik tipleri (`Accept`), daha önceki ziyaretlerden kalan çerezler (`Cookie`) gibi ek bilgiler.
3. **Sunucu İşlemi:** Web sunucusu (örn. Apache, Nginx) isteği alır. İstenen kaynağı (dosya, script vb.) bulur, gerekirse bir uygulama sunucusunu (örn. PHP-FPM) çalıştırır ve bir HTTP yanıtı oluşturur. (Bu süreç `apache_query.png` benzeri bir diagramda gösterilebilir).
4. **HTTP Yanıtı:** Sunucu, tarayıcıya bir HTTP yanıtı gönderir. Bu yanıt şunları içerir:
   * Durum Kodu: `200 OK` (başarılı), `404 Not Found` (bulunamadı), `301 Moved Permanently` (yönlendirme), `500 Internal Server Error` (sunucu hatası) vb.
   * Başlıklar (Headers): İçerik tipi (`Content-Type`), içerik uzunluğu (`Content-Length`), sunucu bilgisi (`Server`), çerez ayarlama (`Set-Cookie`) vb.
   * İçerik (Body): İstenen HTML sayfası, resim dosyası veya diğer veriler.
5. **Sayfa Gösterimi:** Tarayıcı, aldığı yanıtı (genellikle HTML) işler, gerekli diğer kaynakları (CSS, JavaScript, resimler) istemek için ek HTTP istekleri yapar ve son olarak sayfayı kullanıcıya gösterir.

**Port Numaraları ve IANA:**\
Standart port numaraları (0-1023 arası "well-known ports") IANA (Internet Assigned Numbers Authority) tarafından yönetilir ve belirli servisler için ayrılmıştır (örn. 80 HTTP, 443 HTTPS, 22 SSH, 25 SMTP). Tarayıcılar, protokol belirtildiğinde (http\:// veya https\://) bu varsayılan portları otomatik olarak kullanır, bu nedenle adres çubuğuna `:80` veya `:443` yazmak genellikle gerekmez.


# Nameserver Servisleri

Alan Adı Sistemi (DNS - Domain Name System), internetin telefon rehberi gibidir; insanların okuyabildiği alan adlarını (`www.example.com`) bilgisayarların anlayabildiği IP adreslerine (`192.0.2.1`) çevirir. DNS servisleri temel olarak iki ana role ayrılır:

1. **Yetkili (Authoritative) Sunucular:** Belirli bir alan adı (zone) hakkındaki kesin ve orijinal bilgileri (kayıtları) tutan sunuculardır. Bir alan adının sahibi tarafından yönetilirler. Örneğin, `example.com`'un yetkili sunucusu, `www.example.com`'un IP adresini bilir.
2. **Önbellekleyici/Tekrarlayıcı (Caching/Recursive) Sunucular:** Kullanıcılardan veya uygulamalardan gelen DNS sorgularını alır ve yanıtı bulmak için hiyerarşik olarak diğer DNS sunucularını (kök sunucular, TLD sunucuları, yetkili sunucular) sorgular. Bulduğu yanıtı hem istemciye iletir hem de belirli bir süre (TTL - Time To Live) kendi önbelleğinde saklar. İnternet servis sağlayıcılarının sunduğu DNS sunucuları veya Google (`8.8.8.8`), Cloudflare (`1.1.1.1`) gibi genel DNS sunucuları bu tiptedir.

Bir sunucu her iki rolü de üstlenebilir (örn. BIND), ancak genellikle güvenlik ve performans nedenleriyle bu roller ayrılır. Örneğin, sadece yerel ağa hizmet veren bir caching/recursive sunucu (örn. Unbound) ve sadece belirli alan adları için dışarıya hizmet veren yetkili sunucular (örn. Knot DNS, PowerDNS, BIND) kullanmak yaygındır. Bu bölümde, hem yetkili hem de recursive özelliklere sahip olabilen **BIND (Berkeley Internet Name Domain)** yazılımı üzerinden temel kavramlar ve yapılandırma ele alınacaktır.

## DNS Kayıt Tipleri

Bir alan adı (zone) dosyası, o alan adı hakkındaki bilgileri içeren çeşitli **kayıt (record)** türlerinden oluşur. En sık kullanılanlar şunlardır:

| Kayıt Tipi | Açıklama                                                                                                                                                                                                                                                       | Örnek Değer (rackdc.com için)                           |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
| **SOA**    | **Start of Authority:** Alan adının temel bilgilerini (yetkili sunucu, yönetici e-postası, seri numarası, zamanlama ayarları) içerir. Her zone dosyasında bir tane olmalıdır.                                                                                  | (Detayı aşağıda)                                        |
| **NS**     | **Name Server:** Alan adı için yetkili olan nameserver'ların adlarını belirtir.                                                                                                                                                                                | `ns1.rackdc.com.`                                       |
| **A**      | **Address (IPv4):** Bir ana bilgisayar adını (hostname) bir IPv4 adresine eşler.                                                                                                                                                                               | `rackdc.com. A 192.0.2.1`                               |
| **AAAA**   | **Address (IPv6):** Bir ana bilgisayar adını bir IPv6 adresine eşler.                                                                                                                                                                                          | `rackdc.com. AAAA 2001:db8::1`                          |
| **CNAME**  | **Canonical Name:** Bir alan adına takma ad (alias) tanımlar. Sorgu yapıldığında, CNAME'in işaret ettiği asıl isme yönlendirme yapılır ve onun kaydı (genellikle A veya AAAA) döndürülür. Aşırı kullanımı ek sorgulara neden olabilir.                         | `www CNAME rackdc.com.`                                 |
| **MX**     | **Mail Exchanger:** Alan adına gönderilen e-postaları kabul edecek posta sunucularını ve önceliklerini belirtir (düşük sayı daha yüksek öncelik). Değer olarak IP değil, hostname kullanılmalıdır.                                                             | `rackdc.com. MX 10 mail.rackdc.com.`                    |
| **TXT**    | **Text:** Alan adıyla ilgili rastgele metin bilgileri saklamak için kullanılır. Özellikle SPF (Sender Policy Framework), DKIM (DomainKeys Identified Mail) gibi e-posta doğrulama mekanizmaları ve alan adı sahipliği doğrulama için yaygın olarak kullanılır. | `rackdc.com. TXT "v=spf1 include:_spf.google.com ~all"` |
| **SRV**    | **Service Locator:** Belirli bir servis için sunucu ve port bilgilerini bulmak için kullanılır (örn. SIP, LDAP, Kerberos).                                                                                                                                     |                                                         |
| **PTR**    | **Pointer:** Bir IP adresini bir ana bilgisayar adına eşler (Ters DNS çözümlemesi - Reverse DNS). Genellikle IP adres bloklarının sahibi tarafından özel `in-addr.arpa` (IPv4) veya `ip6.arpa` (IPv6) zone'larında tanımlanır.                                 | `1.2.0.192.in-addr.arpa. PTR server.example.com.`       |

**Not:** Alan adlarının sonundaki `.` (nokta) işareti, alan adının tam ve kök dizinden itibaren belirtildiğini ifade eder (Fully Qualified Domain Name - FQDN). Eğer sonda nokta yoksa, BIND genellikle zone'un kendi adını (SOA kaydındaki) sona ekleyerek adı tamamlamaya çalışır. Örneğin, `rackdc.com.` zone dosyasında `www` yazmak `www.rackdc.com.` anlamına gelirken, `mail.example.com.` yazmak tam olarak o adresi ifade eder.

## BIND Kurulumu ve Yapılandırması

BIND DNS sunucusu (genellikle `bind` veya `bind9` paket adıyla) çoğu Linux dağıtımının standart depolarında bulunur.

```bash
# RHEL/CentOS/Fedora
sudo dnf install bind bind-utils -y 

# Debian/Ubuntu
sudo apt update && sudo apt install bind9 bind9utils bind9-doc -y
```

(`bind-utils` paketi `dig`, `nslookup` gibi araçları içerir).

Ana yapılandırma dosyası genellikle `/etc/named.conf` (RHEL tabanlı) veya `/etc/bind/named.conf` (Debian tabanlı)'dır. Zone dosyaları ise `/var/named/` (RHEL) veya `/etc/bind/` (Debian) gibi dizinlerde tutulabilir.

### `named.conf` Temel Ayarları

`named.conf` dosyası, BIND'ın genel çalışma şeklini, hangi zone'lardan sorumlu olduğunu ve güvenlik ayarlarını belirler.

* **ACL (Access Control List):** Belirli IP adreslerini veya ağları gruplamak için kullanılır. Genellikle `allow-recursion` veya `allow-transfer` gibi direktiflerde kullanılır.

  ```
  acl "trusted_clients" {
      localhost;       # Sunucunun kendisi
      192.168.1.0/24;  # Yerel ağ
      <diger_guvenilir_ip>;
  };

  acl "slave_servers" {
      <slave_sunucu_1_ip>;
      <slave_sunucu_2_ip>;
  };
  ```
* **Options Bloğu:** Genel ayarları içerir.

  ```
  options {
      directory "/var/named"; // Zone dosyalarının bulunduğu dizin (RHEL)
      // directory "/etc/bind"; // (Debian)

      // Hangi IP ve portlarda dinlenecek?
      listen-on port 53 { localhost; 192.168.1.10; }; // Sadece localhost ve belirli bir IP
      // listen-on port 53 { any; }; // Tüm IPv4 arayüzleri (dikkatli kullanın!)
      listen-on-v6 port 53 { ::1; }; // Sadece IPv6 localhost
      // listen-on-v6 port 53 { any; }; // Tüm IPv6 arayüzleri

      // Kimler recursive sorgu yapabilir? (Sadece caching/recursive sunucu ise)
      allow-recursion { trusted_clients; }; 
      // Yetkili sunucu ise genellikle: allow-recursion { none; };

      // Kimler zone transferi yapabilir? (Master sunucu ise)
      allow-transfer { slave_servers; }; 
      // Slave veya sadece caching ise: allow-transfer { none; };

      // Güvenlik ve performans ayarları
      dnssec-validation auto; // DNSSEC doğrulaması (recursive sunucu için)
      // dnssec-enable yes; // DNSSEC'i etkinleştir (yetkili sunucu için)
      
      version "Not Available"; // Versiyon bilgisini gizle
      recursion yes; // Recursive sorgulara izin ver (caching/recursive ise)
      // recursion no; // (Yetkili sunucu ise)
  };
  ```

  **Güvenlik Notları:**

  * `listen-on`: Sadece gerekli IP adreslerinde dinleme yapın. `any` kullanmaktan kaçının veya firewall ile koruyun.
  * `allow-recursion`: İnternete açık bir sunucuda `any` olarak bırakmak, sunucunuzun DNS amplification saldırılarında kullanılmasına yol açabilir. Sadece güvendiğiniz IP'lere izin verin veya `none` yapın.
  * `allow-transfer`: Zone transferini sadece slave sunucularınıza izin verin. `none` olarak bırakmak slave'lerin zone'u çekmesini engeller.
* **Zone Tanımları:** Sunucunun yetkili olduğu (master veya slave) veya özel olarak ele aldığı (örn. root hints) zone'ları tanımlar.

  ```
  // Kök sunucu bilgilerini içeren dosya (hint zone)
  zone "." IN {
      type hint;
      file "named.ca"; // veya named.root
  };

  // Localhost için gerekli zone'lar
  zone "localhost" IN {
      type master;
      file "named.localhost";
      allow-update { none; };
  };
  zone "1.0.0.127.in-addr.arpa" IN {
      type master;
      file "named.loopback";
      allow-update { none; };
  };

  // Yönetilen bir alan adı için master zone tanımı
  zone "rackdc.com" IN {
      type master;
      file "rackdc.com.db"; // Zone dosyasının adı (/var/named/ veya /etc/bind/ altında)
      allow-transfer { slave_servers; }; // Slave'lere transfer izni
      // notify yes; // Değişiklik olduğunda slave'lere haber ver (varsayılan)
  };

  // Başka bir sunucudan çekilen slave zone tanımı
  zone "ornekalanadi.com" IN {
      type slave;
      file "slaves/ornekalanadi.com.db"; // Slave zone dosyasının kaydedileceği yer
      masters { <master_sunucu_ip>; }; // Master sunucunun IP adresi
      // allow-notify { <master_sunucu_ip>; }; // Sadece master'dan gelen notify'ları kabul et
  };
  ```

### Zone Dosyası Örneği (`/var/named/rackdc.com.db`)

```
$TTL 14400      ; Varsayılan TTL (Time To Live) - 4 saat
@       IN      SOA     ns1.rackdc.com. hostmaster.rackdc.com. (
                        2023102701    ; Serial (YYYYMMDDNN formatı - HER DEĞİŞİKLİKTE ARTIRILMALI!)
                        7200          ; Refresh (Slave'lerin ne sıklıkla kontrol edeceği - 2 saat)
                        3600          ; Retry (Başarısız kontrolden sonra tekrar deneme süresi - 1 saat)
                        1209600       ; Expire (Slave'in master'a ulaşamazsa veriyi ne kadar geçerli sayacağı - 2 hafta)
                        3600          ; Minimum TTL (Negatif cevapların önbellekte kalma süresi - 1 saat)
                        )

; Name Server (NS) Kayıtları - Bu alan adı için yetkili sunucular
@               IN      NS      ns1.rackdc.com.
@               IN      NS      ns2.rackdc.com.

; NS kayıtlarına karşılık gelen A/AAAA (Glue) Kayıtları (Eğer NS'ler aynı domaindeyse)
ns1             IN      A       192.0.2.1
ns1             IN      AAAA    2001:db8::1
ns2             IN      A       192.0.2.2
ns2             IN      AAAA    2001:db8::2

; Mail Exchanger (MX) Kayıtları - E-postaları kabul edecek sunucular
@               IN      MX      10 mail.rackdc.com.
@               IN      MX      20 backupmail.rackdc.com.

; Host (A/AAAA) Kayıtları
@               IN      A       192.0.2.10      ; Alan adının kendisi (rackdc.com)
@               IN      AAAA    2001:db8::10
www             IN      A       192.0.2.10      ; www.rackdc.com
www             IN      AAAA    2001:db8::10
mail            IN      A       192.0.2.20      ; mail.rackdc.com
backupmail      IN      A       192.0.2.21      ; backupmail.rackdc.com
ftp             IN      CNAME   www             ; ftp.rackdc.com, www ile aynı IP'ye yönlenir

; TXT Kayıtları (Örnek: SPF)
@               IN      TXT     "v=spf1 mx -all" 
```

**Önemli:** Zone dosyasında her değişiklik yapıldığında, SOA kaydındaki **seri numarası mutlaka artırılmalıdır**. Aksi takdirde slave sunucular değişikliği algılamaz ve zone transferi yapmaz. YYYYMMDDNN formatı yaygın bir pratiktir.

## Servis Yönetimi

BIND servisi (genellikle `named` veya `bind9`) systemd ile yönetilir:

```bash
# Servisi başlat
sudo systemctl start named 

# Servisi durdur
sudo systemctl stop named

# Servisi yeniden başlat
sudo systemctl restart named

# Sistem başlangıcında otomatik çalışmasını sağla
sudo systemctl enable named

# Sistem başlangıcında otomatik çalışmasını engelle
sudo systemctl disable named

# Servisin durumunu kontrol et
sudo systemctl status named
```

Zone dosyalarında değişiklik yaptıktan sonra BIND'ın bu değişiklikleri yeniden yüklemesi için `rndc reload` komutu kullanılır (servisi yeniden başlatmaya gerek kalmaz):

```bash
sudo rndc reload
# veya belirli bir zone için:
# sudo rndc reload rackdc.com
```

`named.conf` dosyasında yapılan değişiklikler için ise genellikle servisi yeniden başlatmak (`sudo systemctl restart named`) gerekir. Yapılandırma dosyasının doğruluğunu kontrol etmek için `named-checkconf` komutu kullanılabilir. Zone dosyalarının doğruluğunu kontrol etmek için `named-checkzone <zone_adı> <zone_dosyası>` komutu kullanılır.


# Apache

Apache HTTP Sunucusu (genellikle kısaca "Apache" veya RHEL tabanlı sistemlerde "httpd" olarak anılır), dünyanın en yaygın kullanılan açık kaynaklı web sunucusu yazılımlarından biridir. Apache Software Foundation tarafından geliştirilir ve Apache Lisansı altında dağıtılır. HTTP ve HTTPS protokolleri üzerinden web içeriği sunmak için kullanılır.

## Temel Özellikler

* **Modüler Yapı:** Apache'nin işlevselliği, dinamik olarak yüklenebilen modüller aracılığıyla genişletilebilir (örn. SSL/TLS, URL yeniden yazma, proxy, kimlik doğrulama modülleri).
* **Esnek Yapılandırma:** Direktif tabanlı yapılandırma dosyaları (`httpd.conf`, `.htaccess`) ile detaylı kontrol imkanı sunar.
* **Sanal Ana Bilgisayarlar (Virtual Hosts):** Tek bir sunucu üzerinde birden fazla web sitesini barındırmaya olanak tanır.
* **Platform Bağımsızlığı:** Çeşitli Unix benzeri sistemlerde (Linux, BSD) ve Windows üzerinde çalışabilir.
* **Geniş Topluluk Desteği:** Yaygın kullanımı sayesinde geniş bir kullanıcı topluluğuna ve bol miktarda belgeye sahiptir.

## Kurulum (Paket Yöneticisi ile - Önerilen)

Apache'yi kaynak koddan derlemek yerine, dağıtımınızın paket yöneticisini kullanmak **şiddetle tavsiye edilir**. Bu, kurulumu basitleştirir, güncellemeleri kolaylaştırır ve sistemle uyumluluğu sağlar.

* **RHEL Tabanlı (CentOS Stream, Rocky, AlmaLinux, Fedora):**\
  Paket adı genellikle `httpd`'dir. SSL modülü (`mod_ssl`) ayrı kurulabilir.

  ```bash
  sudo dnf install httpd mod_ssl -y
  ```
* **Debian Tabanlı (Debian, Ubuntu, Mint):**\
  Paket adı genellikle `apache2`'dir. SSL modülü genellikle varsayılan olarak gelir veya `a2enmod ssl` ile etkinleştirilir.

  ```bash
  sudo apt update
  sudo apt install apache2 -y
  ```

## Servis Yönetimi (`systemctl`)

Apache servisi systemd ile yönetilir. Servis adı dağıtıma göre değişir:

* **RHEL Tabanlı:** `httpd.service`
* **Debian Tabanlı:** `apache2.service`

```bash
# Servisi başlatma
sudo systemctl start httpd # veya apache2

# Servisi durdurma
sudo systemctl stop httpd # veya apache2

# Servisi yeniden başlatma
sudo systemctl restart httpd # veya apache2

# Yapılandırmayı yeniden yükleme (daha hızlı)
sudo systemctl reload httpd # veya apache2

# Servisin durumunu kontrol etme
sudo systemctl status httpd # veya apache2

# Sistem başlangıcında otomatik çalışmasını sağlama
sudo systemctl enable httpd # veya apache2

# Sistem başlangıcında otomatik çalışmasını engelleme
sudo systemctl disable httpd # veya apache2
```

## Yapılandırma Dosyaları ve Yapısı

Apache'nin yapılandırma dosyalarının konumu ve organizasyonu dağıtım aileleri arasında farklılık gösterir:

**1. RHEL Tabanlı Sistemler (`/etc/httpd/`)**

* **Ana Yapılandırma:** `/etc/httpd/conf/httpd.conf`
* **Modül Yapılandırmaları:** `/etc/httpd/conf.modules.d/`
* **Ek Yapılandırmalar/Sanal Ana Bilgisayarlar:** `/etc/httpd/conf.d/`
  * Genellikle sanal ana bilgisayar (Virtual Host) tanımları bu dizine `.conf` uzantılı dosyalar halinde eklenir (örn. `/etc/httpd/conf.d/vhost-example.com.conf`).
  * `httpd.conf` dosyasının sonunda genellikle `IncludeOptional conf.d/*.conf` satırı bulunur.

**2. Debian Tabanlı Sistemler (`/etc/apache2/`)**

* **Ana Yapılandırma:** `/etc/apache2/apache2.conf`
* **Portlar:** `/etc/apache2/ports.conf`
* **Modüller:**
  * Mevcut Modüller: `/etc/apache2/mods-available/`
  * Etkin Modüller: `/etc/apache2/mods-enabled/` (buradakiler `mods-available`'a sembolik linklerdir)
  * Etkinleştirme/Devre Dışı Bırakma: `a2enmod <modül_adı>`, `a2dismod <modül_adı>`
* **Site Yapılandırmaları (Sanal Ana Bilgisayarlar):**
  * Mevcut Siteler: `/etc/apache2/sites-available/` (örn. `example.com.conf`)
  * Etkin Siteler: `/etc/apache2/sites-enabled/` (buradakiler `sites-available`'a sembolik linklerdir)
  * Etkinleştirme/Devre Dışı Bırakma: `a2ensite <site_dosya_adı>`, `a2dissite <site_dosya_adı>`
* **Ek Yapılandırma Parçaları:**
  * Mevcut Yapılandırmalar: `/etc/apache2/conf-available/`
  * Etkin Yapılandırmalar: `/etc/apache2/conf-enabled/`
  * Etkinleştirme/Devre Dışı Bırakma: `a2enconf <conf_dosya_adı>`, `a2disconf <conf_dosya_adı>`

Debian tabanlı sistemlerdeki bu yapı, yapılandırmayı daha modüler hale getirir ve siteleri/modülleri kolayca etkinleştirip devre dışı bırakmayı sağlar.

## Temel Sanal Ana Bilgisayar (Virtual Host) Yapılandırması (Apache 2.4+)

Aşağıda, `example.com` alan adı için basit bir sanal ana bilgisayar tanımı örneği verilmiştir (Apache 2.4 ve sonrası sözdizimi ile).

**RHEL Tabanlı (`/etc/httpd/conf.d/example.com.conf`):**

```apache
<VirtualHost *:80>
    ServerAdmin webmaster@example.com
    ServerName example.com
    ServerAlias www.example.com # İsteğe bağlı ek alan adları

    DocumentRoot /var/www/example.com/html # Web sitesi dosyalarının konumu

    ErrorLog /var/log/httpd/example.com-error.log
    CustomLog /var/log/httpd/example.com-access.log combined

    <Directory "/var/www/example.com/html">
        AllowOverride None # .htaccess kullanımını kontrol eder
        Require all granted # Apache 2.4+ erişim kontrolü
    </Directory>
</VirtualHost>
```

**Debian Tabanlı (`/etc/apache2/sites-available/example.com.conf`):**

```apache
<VirtualHost *:80>
    ServerAdmin webmaster@example.com
    ServerName example.com
    ServerAlias www.example.com

    DocumentRoot /var/www/example.com/html 

    ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined

    <Directory "/var/www/example.com/html">
        AllowOverride None
        Require all granted
    </Directory>
</VirtualHost>
```

* `<VirtualHost *:80>`: Port 80'e gelen tüm IP adreslerindeki istekler için sanal ana bilgisayarı tanımlar. HTTPS için `<VirtualHost *:443>` kullanılır.
* `ServerName`: Sanal ana bilgisayarın birincil alan adı.
* `ServerAlias`: İsteğe bağlı ek alan adları.
* `DocumentRoot`: Bu siteye ait web dosyalarının bulunduğu kök dizin.
* `ErrorLog`, `CustomLog`: Bu siteye özel log dosyaları.
* `<Directory ...>`: Belirtilen dizin için erişim izinleri ve seçenekleri tanımlar.
  * `AllowOverride None`: `.htaccess` dosyalarının direktifleri geçersiz kılmasına izin verilmez (daha güvenli ve performanslı).
  * `Require all granted`: Apache 2.4'te dizine erişime izin verir. Eski `Order allow,deny` ve `Allow from all` direktiflerinin yerini almıştır.

Debian tabanlı sistemlerde, bu dosyayı oluşturduktan sonra siteyi etkinleştirmek gerekir:

```bash
sudo a2ensite example.com.conf
sudo systemctl reload apache2
```

## Sunucu Durumu ve Bilgisi (mod\_status, mod\_info)

Apache'nin çalışma durumunu (aktif bağlantılar, yük vb.) izlemek için `mod_status`, yapılandırma ve modül bilgilerini görmek için `mod_info` modülleri kullanılabilir. Bu modüller genellikle ayrı yapılandırma dosyalarıyla etkinleştirilir ve güvenlik nedeniyle erişimleri kısıtlanmalıdır.

**Örnek Yapılandırma (Debian: `/etc/apache2/conf-available/server-status.conf`):**

```apache
<IfModule mod_status.c>
    <Location /server-status>
        SetHandler server-status
        Require local # Sadece localhost'tan erişime izin ver
        # Require ip 192.168.1.0/24 # Belirli bir IP bloğuna izin ver
    </Location>
    ExtendedStatus On # Daha detaylı bilgi göster
</IfModule>
```

Etkinleştirmek için:

```bash
sudo a2enconf server-status
sudo a2enmod status # Gerekliyse modülü de etkinleştir
sudo systemctl reload apache2
```

Ardından `http://localhost/server-status` adresinden erişilebilir. `mod_info` için de benzer bir yapılandırma (`<Location /server-info>`) yapılır.

## HTTPS/TLS (SSL)

Güvenli web siteleri için HTTPS (HTTP over TLS/SSL) kullanmak zorunludur. Apache'de HTTPS'i etkinleştirmek için `mod_ssl` modülünün aktif olması, 443 portunun dinlenmesi ve bir SSL sertifikasının (genellikle Let's Encrypt ile ücretsiz alınabilir) yapılandırılması gerekir. Sanal ana bilgisayar tanımı `<VirtualHost *:443>` bloğu içinde yapılır ve `SSLEngine on`, `SSLCertificateFile`, `SSLCertificateKeyFile` gibi direktifler eklenir.

Apache, esnekliği ve geniş modül ekosistemi ile güçlü bir web sunucusudur. Alternatifi olarak Nginx, özellikle yüksek trafikli sitelerde ve ters proxy olarak popülerlik kazanmıştır.


# PHP-FPM

PHP, web geliştirmede yaygın olarak kullanılan popüler bir betik dilidir. PHP kodunu bir web sunucusu (Apache, Nginx vb.) ile çalıştırmanın çeşitli yolları vardır. Eski yöntemlerden biri Apache'nin `mod_php` modülünü kullanmaktı, ancak bu yöntem genellikle daha az esnek ve performanslıdır.

Modern ve önerilen yaklaşım, **PHP-FPM** (FastCGI Process Manager) kullanmaktır. PHP-FPM, PHP için alternatif bir FastCGI daemon'ıdır ve web sunucusundan bağımsız olarak çalışır. Web sunucusu, gelen PHP isteklerini FastCGI protokolü üzerinden PHP-FPM'e iletir, PHP-FPM isteği işler ve sonucu web sunucusuna geri gönderir.

**PHP-FPM'in Avantajları:**

* **Performans:** Genellikle `mod_php`'den daha iyi performans sunar.
* **Esneklik:** Farklı web siteleri veya uygulamalar için ayrı PHP-FPM havuzları (pools) tanımlanabilir. Her havuz farklı kullanıcı/grup kimliğiyle, farklı PHP ayarlarıyla (`php.ini`) ve farklı kaynak limitleriyle çalıştırılabilir. Bu, güvenlik ve izolasyonu artırır.
* **Kaynak Yönetimi:** İşlem yönetimi (process management - `pm`) ayarları (`static`, `dynamic`, `ondemand`) ile kaynak kullanımı daha iyi kontrol edilebilir.
* **Web Sunucusu Bağımsızlığı:** Hem Apache hem de Nginx gibi farklı web sunucularıyla kullanılabilir.

## Kurulum

PHP-FPM ve ilgili PHP paketleri genellikle dağıtımın paket yöneticisi ile kurulur. PHP sürümü (örn. 8.1, 8.2) dağıtıma göre değişir. Belirli bir sürümü kurmak için ek depolar (örn. REMI, Ondřej Surý PPA) gerekebilir.

* **RHEL Tabanlı (dnf):** (Genellikle `remi-release` deposu etkinleştirildikten sonra)

  ```bash
  # Örnek: PHP 8.2 ve yaygın modülleri kurma
  sudo dnf module enable php:remi-8.2 -y 
  sudo dnf install php php-fpm php-mysqlnd php-gd php-xml php-mbstring php-intl -y
  ```
* **Debian Tabanlı (apt):** (Genellikle `ondrej/php` PPA'sı eklendikten sonra veya dağıtımın kendi sürümü)

  ```bash
  # Örnek: PHP 8.2 ve yaygın modülleri kurma
  sudo apt update
  sudo apt install php8.2 php8.2-fpm php8.2-mysql php8.2-gd php8.2-xml php8.2-mbstring php8.2-intl -y
  ```

## Servis Yönetimi (`systemctl`)

PHP-FPM servisi systemd ile yönetilir. Servis adı genellikle PHP sürümünü içerir.

```bash
# Servisi başlatma (Örnek: PHP 8.2)
sudo systemctl start php8.2-fpm 

# Sistem başlangıcında otomatik çalışmasını sağlama
sudo systemctl enable php8.2-fpm

# Servisin durumunu kontrol etme
sudo systemctl status php8.2-fpm

# Yapılandırma değişikliğinden sonra yeniden başlatma
sudo systemctl restart php8.2-fpm 
```

## PHP-FPM Havuz (Pool) Yapılandırması

PHP-FPM, farklı ayarlar ve kullanıcılarla çalışabilen **havuzlar (pools)** kullanır. Varsayılan havuz genellikle `www` olarak adlandırılır ve yapılandırması `/etc/php/<sürüm>/fpm/pool.d/www.conf` (Debian/Ubuntu) veya `/etc/php-fpm.d/www.conf` (RHEL/CentOS) gibi dosyalarda bulunur.

Her web sitesi veya uygulama için ayrı bir havuz oluşturmak iyi bir pratiktir.

**Örnek Havuz Yapılandırması (`/etc/php-fpm.d/example.com.conf`):**

```ini
[example.com] ; Havuz adı

; Çalıştırılacak Kullanıcı ve Grup
user = example_user
group = example_group

; Dinlenecek Soket (Unix soketi önerilir)
listen = /run/php-fpm/example.com.sock 

; Soket Sahibi ve Grubu (Web sunucusunun erişebilmesi için önemlidir)
listen.owner = nginx ; veya apache, httpd, www-data vb.
listen.group = nginx
listen.mode = 0660

; İşlem Yönetimi (Process Management)
pm = dynamic ; veya ondemand, static
pm.max_children = 10     ; Aynı anda çalışacak maksimum işlem sayısı
pm.start_servers = 2     ; Başlangıçta çalıştırılacak işlem sayısı (dynamic için)
pm.min_spare_servers = 1 ; Minimum boşta bekleyecek işlem sayısı (dynamic için)
pm.max_spare_servers = 3 ; Maksimum boşta bekleyecek işlem sayısı (dynamic için)
; pm.process_idle_timeout = 10s; ; Boştaki işlemin ne kadar süre sonra kapatılacağı (ondemand için)
; pm.max_requests = 500    ; Bir işlemin kaç istekten sonra yeniden başlatılacağı

; PHP Ayarları (isteğe bağlı, php.ini'yi geçersiz kılar)
; php_admin_value[memory_limit] = 128M
; php_admin_flag[log_errors] = on
; php_admin_value[error_log] = /var/log/php-fpm/example.com-error.log
```

Yeni bir havuz dosyası oluşturduktan veya mevcut olanı değiştirdikten sonra PHP-FPM servisini yeniden başlatmanız (`sudo systemctl restart php<sürüm>-fpm`) gerekir.

## Web Sunucusu Yapılandırması

Web sunucusunun, PHP dosyalarına gelen istekleri ilgili PHP-FPM havuzunun dinlediği sokete (veya porta) FastCGI protokolü üzerinden iletmesi gerekir.

**1. Apache ile PHP-FPM (mod\_proxy\_fcgi kullanarak)**

Gerekli Apache modüllerini etkinleştirin:

```bash
# Debian/Ubuntu
sudo a2enmod proxy proxy_fcgi setenvif

# RHEL/CentOS (genellikle httpd ile gelir, conf.modules.d/ içinde kontrol edin)
# Gerekirse: sudo systemctl restart httpd 
sudo systemctl restart apache2 # Debian/Ubuntu için
```

Apache sanal ana bilgisayar yapılandırmasına (`<VirtualHost>` bloğu içine) aşağıdaki gibi bir direktif ekleyin (Unix soketi kullanarak):

```apache
# .php dosyalarına gelen istekleri PHP-FPM soketine yönlendir
<FilesMatch \.php$>
    SetHandler "proxy:unix:/run/php-fpm/example.com.sock|fcgi://localhost/"
</FilesMatch>

# Veya TCP soketi kullanılıyorsa (örn. 127.0.0.1:9001):
# <FilesMatch \.php$>
#    SetHandler "proxy:fcgi://127.0.0.1:9001"
# </FilesMatch>

# index.php'nin varsayılan dizin indeksi olmasını sağla
DirectoryIndex index.php index.html
```

Yapılandırmayı kontrol edip Apache'yi yeniden yükleyin:

```bash
sudo apachectl configtest
sudo systemctl reload apache2 # veya httpd
```

**2. Nginx ile PHP-FPM**

Nginx sanal ana bilgisayar yapılandırmasındaki (`server` bloğu içine) `location` bloğunu PHP isteklerini işleyecek şekilde düzenleyin (Unix soketi kullanarak):

```nginx
server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/example.com/html;
    index index.php index.html index.htm;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf; # Dağıtımınızdaki standart fastcgi parametrelerini içerir

        # PHP-FPM soketine yönlendir
        fastcgi_pass unix:/run/php-fpm/example.com.sock;

        # Veya TCP soketi kullanılıyorsa:
        # fastcgi_pass 127.0.0.1:9001;
    }

    # .htaccess dosyalarına erişimi engelle (güvenlik)
    location ~ /\.ht {
        deny all;
    }
}
```

Yapılandırmayı kontrol edip Nginx'i yeniden yükleyin:

```bash
sudo nginx -t
sudo systemctl reload nginx
```

PHP-FPM, modern PHP uygulamalarını web sunucularıyla entegre etmek için standart ve performanslı bir yöntemdir. Farklı havuzlar kullanarak uygulamalar arasında daha iyi izolasyon ve kaynak yönetimi sağlar.


# FTP/FTPS/SFTP

Dosya Transfer Protokolü (FTP - File Transfer Protocol), ağ üzerindeki bilgisayarlar arasında dosya aktarımı yapmak için kullanılan eski ve temel bir protokoldür. Bir istemci-sunucu modeli kullanır; kullanıcı bir FTP istemcisi ile bir FTP sunucusuna bağlanarak dosya yükleyebilir (upload) veya indirebilir (download).

## FTP'nin Güvenlik Zafiyetleri

**Standart FTP protokolü (genellikle TCP port 21 ve 20 kullanılır) doğası gereği güvensizdir.** Hem kullanıcı adı/şifre gibi kimlik bilgileri hem de aktarılan verinin kendisi ağ üzerinde **şifrelenmeden**, düz metin olarak gönderilir. Bu durum, ağ trafiğini dinleyen kötü niyetli kişilerin bu bilgilere kolayca erişmesine olanak tanır. Bu nedenle, **güvenilmeyen ağlarda (özellikle internet üzerinde) standart FTP kullanımından kesinlikle kaçınılmalıdır.**

## Güvenli Alternatifler: FTPS ve SFTP

FTP'nin güvenlik zafiyetlerini gidermek için iki ana alternatif geliştirilmiştir:

1. **FTPS (FTP over TLS/SSL):** Standart FTP protokolünü, web sitelerinde HTTPS için kullanılan TLS/SSL şifreleme katmanı ile sarmalar. Hem kontrol bağlantısı (komutlar, kullanıcı adı/şifre) hem de veri bağlantısı (dosya içeriği) şifrelenebilir. İki modu vardır:
   * **Explicit FTPS:** Bağlantı normal FTP portundan (21) başlar, istemci `AUTH TLS` veya `AUTH SSL` komutuyla şifrelemeyi talep eder.
   * **Implicit FTPS:** Bağlantı doğrudan güvenli bir porttan (genellikle 990) başlar ve tüm iletişim baştan itibaren şifrelenir.\
     FTPS, FTP'nin altyapısını kullandığı için NAT ve güvenlik duvarı yapılandırmalarında bazen zorluklar çıkarabilir (özellikle veri bağlantısı için farklı portlar kullanıldığında).
   * [FTPS](https://github.com/VeriTeknik/linux_kitap/blob/master/internet-servisleri/ftp/ftps.md)
2. **SFTP (SSH File Transfer Protocol):** FTP ile **karıştırılmamalıdır**. SFTP, FTP'den tamamen farklı, modern bir protokoldür ve dosya transferi işlemlerini güvenli bir **SSH (Secure Shell)** bağlantısı üzerinden gerçekleştirir.
   * Tüm iletişim (kimlik bilgileri, komutlar, veri) SSH tüneli içinde şifrelenir.
   * Genellikle standart SSH portunu (22) kullanır, bu da güvenlik duvarı yapılandırmasını basitleştirir.
   * Dosya transferi yanında dizin listeleme, oluşturma, silme, izin değiştirme gibi daha gelişmiş dosya sistemi operasyonlarını destekler.
   * Kimlik doğrulama için SSH anahtarları kullanılabilir.
   * Günümüzde **güvenli dosya transferi için genellikle SFTP tercih edilen yöntemdir.** SFTP sunucu işlevselliği, çoğu Linux sisteminde zaten kurulu olan OpenSSH sunucusu (`sshd`) tarafından sağlanır.
   * [SFTP](/internet-servisleri/ftp/sftp)

## Yaygın Sunucu Yazılımları

* **vsftpd (Very Secure FTP Daemon):** Güvenlik odaklı, hafif ve yaygın olarak kullanılan bir FTP/FTPS sunucusudur.
  * [vsftpd](/internet-servisleri/ftp/vsftpd)
* **ProFTPD:** Çok esnek yapılandırma seçenekleri sunan, modüler yapıda bir FTP/FTPS sunucusudur.
  * [ProFTPD](/internet-servisleri/ftp/proftpd)
* **OpenSSH sshd:** SFTP hizmetini sağlar.

## İstemci Kullanımı

Dosya transferi için çeşitli komut satırı istemcileri (`ftp`, `sftp`, `lftp`, `scp`, `rsync`) ve grafiksel istemciler (FileZilla, WinSCP vb.) mevcuttur.

* [Komut Satırından ftp Kullanımı](/internet-servisleri/ftp/komut-satirindan-ftp-kullanimi) (Not: Bu bölümdeki `ftp` komutu güvensiz protokolü kullanır, `sftp` istemcisi daha güvenlidir.)

Bu bölümdeki diğer dosyalar, farklı FTP sunucularının yapılandırılması ve güvenli alternatifleri hakkında daha detaylı bilgi verecektir.


# vsftpd

`vsftpd`, güvenlik ve performansa odaklanan, yaygın olarak kullanılan bir FTP ve FTPS sunucusudur. Yapılandırması genellikle diğer FTP sunucularına göre daha basit kabul edilir.

**Uyarı:** Standart FTP güvensizdir. Mümkünse, dosya transferi için `vsftpd`'yi FTPS modunda yapılandırın veya daha modern ve genellikle daha kolay yapılandırılan SFTP (OpenSSH `sshd` tarafından sağlanır) kullanın.

## Kurulum

`vsftpd` genellikle dağıtımların standart depolarında bulunur.

* **RHEL Tabanlı (dnf):**

  ```bash
  sudo dnf install vsftpd -y
  ```
* **Debian Tabanlı (apt):**

  ```bash
  sudo apt update
  sudo apt install vsftpd -y
  ```

## Temel Yapılandırma (`/etc/vsftpd.conf`)

Ana yapılandırma dosyası genellikle `/etc/vsftpd.conf`'tur. Aşağıda bazı temel ve güvenlik açısından önemli ayarlar bulunmaktadır (dosyayı `sudo` ile düzenleyin):

```bash
# Anonim girişi engelle (ÖNEMLİ!)
anonymous_enable=NO

# Yerel sistem kullanıcılarının giriş yapmasına izin ver
local_enable=YES

# Kullanıcıların dosya yüklemesine/değiştirmesine izin ver (gerekliyse)
write_enable=YES

# Yerel kullanıcıları kendi ev dizinlerine hapset (chroot) (ÖNEMLİ!)
chroot_local_user=YES
# Eğer chroot edilen ev dizini kullanıcı tarafından yazılabilir ise, 
# güvenlik nedeniyle vsftpd hata verebilir. Bunu aşmak için (dikkatli olun):
allow_writeable_chroot=YES 
# Alternatif olarak, chroot için yazma izni olmayan ayrı bir dizin kullanılabilir.

# Standalone modda çalıştır (xinetd yerine)
listen=YES
# IPv6 dinlemesi için (gerekliyse)
listen_ipv6=YES 

# Yüklemeler için varsayılan umask (022 -> dosyalar 644, dizinler 755)
local_umask=022

# ASCII modunda transferi etkinleştir (bazı eski sistemlerle uyumluluk için gerekebilir)
# ascii_upload_enable=YES
# ascii_download_enable=YES

# Zaman damgalarını GMT olarak göster
use_localtime=NO 

# Bağlantı ve transfer loglarını etkinleştir
xferlog_enable=YES
xferlog_std_format=YES # Standart log formatını kullan
xferlog_file=/var/log/vsftpd.log # Log dosyasının yeri

# Boşta kalma süresi (saniye)
idle_session_timeout=600

# Veri bağlantısı zaman aşımı (saniye)
data_connection_timeout=120

# Banner göster (isteğe bağlı)
ftpd_banner=FTP Sunucusuna Hos Geldiniz.

# Pasif mod için port aralığı (güvenlik duvarında bu portlara izin verilmeli)
# pasv_min_port=40000
# pasv_max_port=40100

# Kullanıcı listesi dosyaları (gerekirse belirli kullanıcılara izin vermek/engellemek için)
# userlist_enable=YES
# userlist_file=/etc/vsftpd.userlist
# userlist_deny=NO # userlist_file'daki kullanıcılara izin ver (YES ise engelle)
```

## FTPS Yapılandırması (TLS/SSL)

FTPS'i etkinleştirmek için `/etc/vsftpd.conf` dosyasına aşağıdaki gibi direktifler eklenir:

```bash
# SSL/TLS'i etkinleştir
ssl_enable=YES

# Anonim kullanıcılar için SSL'i zorunlu kılma (zaten anonim kapalı)
allow_anon_ssl=NO
# Yerel kullanıcılar için hem login hem de veri transferinde SSL'i zorunlu kıl
force_local_data_ssl=YES
force_local_logins_ssl=YES

# Kullanılacak TLS/SSL protokol sürümleri (Sadece modern TLS önerilir)
ssl_tlsv1_2=YES
ssl_sslv2=NO
ssl_sslv3=NO
ssl_tlsv1=NO
ssl_tlsv1_1=NO

# SSL sertifikası ve özel anahtar dosyalarının yolu
# (Genellikle bir SSL sertifikası oluşturmanız veya almanız gerekir, örn. Let's Encrypt)
rsa_cert_file=/etc/ssl/certs/vsftpd.pem # Kendi sertifika dosyanızın yolu
rsa_private_key_file=/etc/ssl/private/vsftpd.pem # Kendi özel anahtar dosyanızın yolu

# Güçlü şifreleme algoritmalarını tercih et
ssl_ciphers=HIGH

# SSL oturumlarının yeniden kullanımıyla ilgili uyumluluk ayarı
require_ssl_reuse=NO 
```

**Not:** FTPS için bir SSL sertifikası ve özel anahtar gereklidir. `openssl` komutu ile kendinden imzalı (self-signed) bir sertifika oluşturabilir veya Let's Encrypt gibi bir otoriteden ücretsiz sertifika alabilirsiniz. Dosya yollarını kendi sertifika konumlarınıza göre ayarlayın.

## Servis Yönetimi (`systemctl`)

Yapılandırma dosyasında değişiklik yaptıktan sonra `vsftpd` servisini yeniden başlatmanız gerekir:

```bash
# Yapılandırmayı kontrol et (bazı dağıtımlarda bu komut olmayabilir)
# vsftpd -olisten=NO /etc/vsftpd.conf 

# Servisi yeniden başlat
sudo systemctl restart vsftpd.service

# Sistem başlangıcında otomatik çalışmasını sağla
sudo systemctl enable vsftpd.service

# Servisin durumunu kontrol et
sudo systemctl status vsftpd.service
```

## Güvenlik Duvarı (Firewall)

`vsftpd`'nin çalışması için güvenlik duvarınızda ilgili portlara izin vermeniz gerekir:

* **Port 21 (TCP):** FTP kontrol bağlantısı.
* **Port 20 (TCP):** FTP veri bağlantısı (Aktif mod - nadiren kullanılır).
* **Pasif Port Aralığı (TCP):** `/etc/vsftpd.conf` içinde `pasv_min_port` ve `pasv_max_port` ile tanımlanan aralık (Pasif mod - yaygın olarak kullanılır).
* **Port 990 (TCP):** Implicit FTPS (eğer yapılandırıldıysa).

Örnek (`firewalld` kullanarak):

```bash
sudo firewall-cmd --permanent --add-service=ftp
# veya belirli portlar:
# sudo firewall-cmd --permanent --add-port=21/tcp
# sudo firewall-cmd --permanent --add-port=40000-40100/tcp # Pasif port aralığı
sudo firewall-cmd --reload
```

`vsftpd`, doğru yapılandırıldığında güvenli bir FTP/FTPS sunucusu olabilir, ancak SFTP'nin genellikle daha basit ve standart bir güvenli dosya transfer çözümü sunduğunu unutmayın.


# ProFTPD

ProFTPD, yüksek düzeyde yapılandırılabilir, modüler ve yaygın olarak kullanılan bir açık kaynaklı FTP ve FTPS sunucusudur. Yapılandırma sözdizimi Apache web sunucusuna oldukça benzer, bu da Apache'ye aşina olan yöneticiler için öğrenmeyi kolaylaştırır.

**Uyarı:** Standart FTP güvensizdir. Mümkünse, dosya transferi için ProFTPD'yi FTPS modunda (`mod_tls` ile) yapılandırın veya daha modern ve genellikle daha kolay yapılandırılan SFTP (OpenSSH `sshd` tarafından sağlanır) kullanın.

## Kurulum

ProFTPD genellikle dağıtımların standart depolarında bulunur.

* **RHEL Tabanlı (dnf):** (EPEL deposu gerekebilir)

  ```bash
  sudo dnf install proftpd proftpd-utils -y 
  # FTPS için openssl gerekebilir (genellikle kuruludur)
  ```
* **Debian Tabanlı (apt):**

  ```bash
  sudo apt update
  sudo apt install proftpd-basic -y 
  # FTPS için: sudo apt install proftpd-mod-crypto -y (veya proftpd-basic içinde olabilir)
  ```

## Temel Yapılandırma (`/etc/proftpd/proftpd.conf`)

Ana yapılandırma dosyası genellikle `/etc/proftpd/proftpd.conf` veya `/etc/proftpd.conf`'tur. Ek yapılandırma dosyaları `/etc/proftpd/conf.d/` veya `/etc/proftpd/modules.conf` gibi yerlerde bulunabilir.

Aşağıda bazı temel direktifler ve güvenlik ayarları bulunmaktadır:

```apache
# Sunucu Adı ve Tipi
ServerName                      "ProFTPD Sunucusu"
ServerType                      standalone # xinetd yerine kendi başına çalışır
DefaultServer                   on

# Port
Port                            21

# Çalıştırılacak Kullanıcı ve Grup
User                            proftpd
Group                           nogroup # veya proftpd

# Maksimum Eşzamanlı Bağlantı
MaxInstances                    30

# Kullanıcıları Ev Dizinlerine Hapsetme (Chroot)
DefaultRoot                     ~   # Kullanıcıyı kendi ev dizinine kilitler
# Belirli bir grup dışındakileri kilitlemek için:
# DefaultRoot ~ !admin_group 

# Geçerli bir kabuğu olmayan kullanıcıların girişine izin ver (örn. /sbin/nologin)
RequireValidShell               off

# Anonim girişi engelle (ÖNEMLİ!)
<Anonymous ~ftp>
  User                          ftp
  Group                         nogroup
  UserAlias                     anonymous ftp
  # Anonim girişi tamamen kapatmak için bu bloğu silin veya:
  <Limit LOGIN>
    DenyAll
  </Limit>
</Anonymous>

# Yükleme/Değiştirme İzinleri
<Directory />
  AllowOverwrite                on
</Directory>
# Daha kısıtlı izinler için <Directory> veya <Limit> blokları kullanılabilir

# Loglama
TransferLog /var/log/proftpd/xferlog
SystemLog   /var/log/proftpd/proftpd.log

# Pasif mod için port aralığı (güvenlik duvarında izin verilmeli)
# PassivePorts                  49152 65534
```

## FTPS Yapılandırması (`mod_tls`)

ProFTPD'de FTPS desteği `mod_tls` modülü ile sağlanır. Bu modülün yüklenmesi ve yapılandırılması gerekir.

1. **Modülü Yükleme/Etkinleştirme:**
   * Debian/Ubuntu'da genellikle `proftpd-mod-crypto` paketi ile gelir.
   * Yapılandırma dosyasında (`modules.conf` veya `proftpd.conf`) `LoadModule mod_tls.c` satırının aktif olduğundan emin olun.
2. **TLS Yapılandırması (`proftpd.conf` veya ayrı bir `tls.conf`):**

   ```apache
   <IfModule mod_tls.c>
       # TLS'i etkinleştir
       TLSEngine               on
       # Loglama
       TLSLog                  /var/log/proftpd/tls.log
       # Sadece güvenli protokolleri kullan (TLSv1.2 ve sonrası)
       TLSProtocol             TLSv1.2 TLSv1.3 
       # Sertifika ve anahtar dosyaları
       TLSRSACertificateFile     /etc/ssl/certs/proftpd.crt # Kendi sertifika dosyanız
       TLSRSACertificateKeyFile  /etc/ssl/private/proftpd.key # Kendi özel anahtarınız
       # TLSCACertificateFile    /etc/ssl/certs/myca.crt # İstemci sertifikası doğrulaması için (isteğe bağlı)
       # TLSVerifyClient off # İstemci sertifikası isteme (genellikle off)
       
       # Bağlantı gereksinimleri
       TLSRequired             on # Hem kontrol hem veri bağlantısı için TLS zorunlu
       # veya TLSRequired ctrl+data
       
       # Diğer seçenekler
       TLSOptions              NoCertRequest NoSessionReuseRequired # İstemci sertifikası isteme, oturum yeniden kullanımı zorunlu değil
       TLSRenegotiate          none # Yeniden anlaşmayı kapat
   </IfModule>
   ```

   **Not:** FTPS için bir SSL sertifikası ve özel anahtar gereklidir. `openssl` komutu ile kendinden imzalı (self-signed) bir sertifika oluşturabilir veya Let's Encrypt gibi bir otoriteden ücretsiz sertifika alabilirsiniz. Dosya yollarını kendi sertifika konumlarınıza göre ayarlayın.

## Servis Yönetimi (`systemctl`)

Yapılandırma dosyasında değişiklik yaptıktan sonra `proftpd` servisini yeniden başlatmanız gerekir:

```bash
# Yapılandırmayı kontrol et
sudo proftpd -t

# Servisi yeniden başlat
sudo systemctl restart proftpd.service

# Sistem başlangıcında otomatik çalışmasını sağla
sudo systemctl enable proftpd.service

# Servisin durumunu kontrol et
sudo systemctl status proftpd.service
```

Servis adı dağıtıma göre `proftpd` veya `proftpd-basic` olabilir.

## Güvenlik Duvarı (Firewall)

ProFTPD'nin çalışması için güvenlik duvarınızda ilgili portlara izin vermeniz gerekir:

* **Port 21 (TCP):** FTP/FTPS kontrol bağlantısı.
* **Pasif Port Aralığı (TCP):** `/etc/proftpd/proftpd.conf` içinde `PassivePorts` ile tanımlanan aralık (Pasif mod - FTPS için de gereklidir).
* **Port 990 (TCP):** Implicit FTPS (eğer yapılandırıldıysa).

Örnek (`firewalld` kullanarak):

```bash
sudo firewall-cmd --permanent --add-service=ftp
# veya belirli portlar:
# sudo firewall-cmd --permanent --add-port=21/tcp
# sudo firewall-cmd --permanent --add-port=49152-65534/tcp # Pasif port aralığı
sudo firewall-cmd --reload
```

ProFTPD, esnek yapılandırmasıyla güçlü bir FTP/FTPS sunucusudur, ancak yapılandırması `vsftpd`'ye göre biraz daha karmaşık olabilir. Güvenlik için FTPS'i etkinleştirmek veya SFTP kullanmak önemlidir.


# SFTP

SFTP, dosya transferi ve yönetimi için SSH (Secure Shell) protokolü üzerine inşa edilmiş güvenli bir ağ protokolüdür. Standart FTP veya FTPS ile karıştırılmamalıdır; tamamen farklı bir protokoldür ancak benzer işlevsellik sunar.

SFTP'nin en büyük avantajı, mevcut SSH altyapısını kullanmasıdır. Çoğu Linux sunucusunda OpenSSH sunucusu (`sshd`) zaten kurulu ve çalışır durumdadır ve bu sunucu genellikle SFTP hizmetini de otomatik olarak sağlar. Bu, ayrı bir FTP sunucusu kurma ve yapılandırma ihtiyacını ortadan kaldırır.

## SFTP'nin Avantajları

* **Güvenlik:** Tüm iletişim (kimlik doğrulama, komutlar, veri aktarımı) SSH tarafından şifrelenir.
* **Basitlik:** Genellikle ek sunucu kurulumu gerektirmez (sshd yeterlidir).
* **Tek Port:** Standart SSH portunu (genellikle 22) kullanır, bu da güvenlik duvarı yapılandırmasını basitleştirir.
* **İşlevsellik:** Basit dosya yükleme/indirme işlemlerinin yanı sıra dizin listeleme, oluşturma, silme, yeniden adlandırma, sembolik link oluşturma ve izinleri/sahipliği değiştirme gibi gelişmiş dosya sistemi operasyonlarını destekler.
* **Kimlik Doğrulama:** SSH ile aynı kimlik doğrulama yöntemlerini kullanır (şifre, SSH anahtarları vb.).

## SFTP Sunucu Yapılandırması (OpenSSH `sshd_config`)

SFTP hizmeti genellikle `/etc/ssh/sshd_config` dosyasındaki `Subsystem` direktifi ile etkinleştirilir. Çoğu dağıtımda bu satır varsayılan olarak bulunur ve aktiftir:

```
Subsystem sftp /usr/lib/openssh/sftp-server 
# veya /usr/libexec/openssh/sftp-server gibi farklı bir yol olabilir
```

Bu satır, `sshd`'nin SFTP bağlantı isteklerini nasıl ele alacağını belirtir.

**Kullanıcıları Kendi Ev Dizinlerine Hapsetme (Chroot):**

SFTP kullanıcılarının sadece kendi ev dizinlerini veya belirli bir dizini görmelerini ve bunun dışına çıkamamalarını sağlamak güvenlik açısından önemlidir. Bu, `sshd_config` dosyasında `ChrootDirectory` direktifi ile yapılır. Genellikle belirli bir gruba ait kullanıcılar için uygulanır:

```bash
# Önce sftp kullanıcıları için bir grup oluşturun (eğer yoksa)
# sudo groupadd sftpusers

# sshd_config dosyasını düzenleyin:
# sudo vim /etc/ssh/sshd_config

# Dosyanın sonuna aşağıdaki gibi bir blok ekleyin:

Match Group sftpusers
  ChrootDirectory %h  # Kullanıcıyı kendi ev dizinine (/home/kullanici) hapseder
  # Veya ChrootDirectory /sftp/%u # Kullanıcıyı /sftp/kullanici_adi dizinine hapseder
  ForceCommand internal-sftp # Sadece SFTP erişimine izin ver, SSH kabuğunu engelle
  AllowTcpForwarding no
  X11Forwarding no

# Yapılandırmayı kontrol edip sshd'yi yeniden başlatın
# sudo sshd -t
# sudo systemctl restart sshd
```

**Açıklamalar:**

* `Match Group sftpusers`: Takip eden direktiflerin sadece `sftpusers` grubundaki kullanıcılar için geçerli olacağını belirtir.
* `ChrootDirectory %h`: Kullanıcıyı kendi ev dizinine (`%h`) hapseder. Alternatif olarak, `%u` (kullanıcı adı) değişkenini kullanarak her kullanıcı için özel bir dizin belirleyebilirsiniz (örn. `/srv/sftp/%u`).
* **Önemli:** `ChrootDirectory` ile belirtilen dizinin ve üstündeki tüm dizinlerin sahibinin `root` olması ve başka hiçbir kullanıcı (grup dahil) tarafından **yazılabilir olmaması** gerekir. Kullanıcının dosya yükleyebileceği alt dizinler daha sonra oluşturulup sahibi kullanıcı olarak ayarlanmalıdır. Örneğin, `ChrootDirectory /home/kullanici` kullanılıyorsa, `/home/kullanici` dizininin sahibi `root:root` ve izinleri `755` olmalı, dosya yükleme için `/home/kullanici/upload` gibi bir alt dizin oluşturulup sahibi `kullanici:kullanici` yapılmalıdır.
* `ForceCommand internal-sftp`: Kullanıcı bağlandığında SSH kabuğu yerine doğrudan `sshd`'nin kendi içindeki SFTP sunucusunu çalıştırır. Bu, kullanıcının sadece SFTP yapabilmesini sağlar, SSH ile komut satırı erişimini engeller.
* `AllowTcpForwarding no`, `X11Forwarding no`: Güvenlik amacıyla bu kullanıcılar için port yönlendirme ve X11 yönlendirmeyi devre dışı bırakır.

## SFTP İstemci Kullanımı

Komut satırından `sftp` istemcisi kullanılabilir:

```bash
sftp kullanici@uzak_sunucu
# veya farklı port için:
# sftp -P 2222 kullanici@uzak_sunucu
```

Bağlantı kurulduktan sonra, FTP'ye benzer komutlarla etkileşimli bir oturum başlar:

* `ls`: Uzak dizini listeler.
* `lls`: Yerel dizini listeler.
* `cd <dizin>`: Uzak dizini değiştirir.
* `lcd <dizin>`: Yerel dizini değiştirir.
* `pwd`: Uzak çalışma dizinini gösterir.
* `lpwd`: Yerel çalışma dizinini gösterir.
* `get <uzak_dosya> [yerel_dosya]`: Uzak sunucudan dosya indirir.
* `put <yerel_dosya> [uzak_dosya]`: Uzak sunucuya dosya yükler.
* `mkdir <dizin>`: Uzak dizin oluşturur.
* `rm <dosya>`: Uzak dosyayı siler.
* `rmdir <dizin>`: Uzak dizini siler.
* `help` veya `?`: Komut listesini gösterir.
* `quit` veya `bye` veya `exit`: Oturumu sonlandırır.

Ayrıca FileZilla, WinSCP gibi birçok grafiksel istemci de SFTP protokolünü destekler.

SFTP, güvensiz FTP'ye modern, güvenli ve genellikle daha kolay yönetilebilir bir alternatiftir.


# Komut Satırından ftp Kullanımı

Linux sistemlerde, FTP sunucularına bağlanmak için genellikle `ftp` adında bir komut satırı istemcisi bulunur. Bu istemci, interaktif bir oturum başlatarak FTP sunucusu üzerinde dosya işlemleri yapmanızı sağlar.

**UYARI:** Standart `ftp` istemcisi, güvensiz FTP protokolünü kullanır. Kullanıcı adı, şifre ve aktarılan veriler **şifrelenmeden** gönderilir. Güvenilmeyen ağlarda kullanmaktan **kesinlikle kaçının**. Güvenli dosya transferi için `sftp` istemcisini veya `scp`/`rsync` komutlarını tercih edin.

## Temel `ftp` Komutları

1. **Bağlantı Kurma:**

   ```bash
   ftp <sunucu_adresi_veya_ip>
   ```

   Komut, sunucuya bağlanmayı dener ve genellikle kullanıcı adı (`Name:`) ister. Anonim giriş için `ftp` veya `anonymous` yazılabilir, aksi takdirde kullanıcı adınızı girin. Ardından şifre istenir.
2. **İnteraktif Oturum:**\
   Başarıyla bağlandıktan sonra `ftp>` istemi görünür. Aşağıdaki komutlar kullanılabilir:
   * `ls` veya `dir`: Uzak sunucudaki dosyaları listeler.
   * `cd <dizin>`: Uzak sunucudaki dizini değiştirir.
   * `lcd <dizin>`: Yerel makinedeki dizini değiştirir.
   * `pwd`: Uzak sunucudaki mevcut çalışma dizinini gösterir.
   * `get <uzak_dosya> [yerel_dosya]`: Uzak sunucudan yerel makineye dosya indirir.
   * `put <yerel_dosya> [uzak_dosya]`: Yerel makineden uzak sunucuya dosya yükler.
   * `mget <dosya_deseni>`: Birden fazla dosyayı indirir (joker karakterler kullanılabilir, örn. `mget *.txt`). Genellikle her dosya için onay ister.
   * `mput <dosya_deseni>`: Birden fazla dosyayı yükler.
   * `prompt`: `mget` ve `mput` için onay istemini açar/kapatır.
   * `binary`: Dosya transfer modunu ikili (binary) olarak ayarlar (resimler, programlar vb. için gereklidir).
   * `ascii`: Dosya transfer modunu metin (ASCII) olarak ayarlar (metin dosyaları için). Genellikle `binary` modunu kullanmak daha güvenlidir.
   * `mkdir <dizin>`: Uzak sunucuda dizin oluşturur.
   * `delete <dosya>`: Uzak sunucudaki dosyayı siler.
   * `rmdir <dizin>`: Uzak sunucudaki boş dizini siler.
   * `help` veya `?`: Kullanılabilir komutların listesini gösterir.
   * `bye` veya `quit`: Bağlantıyı kapatır ve istemciden çıkar.

**Örnek Oturum:**

```bash
$ ftp ftp.example.com
Connected to ftp.example.com.
220 (vsFTPd 3.0.3)
Name (ftp.example.com:user): anonymous
331 Please specify the password.
Password: <e-posta_adresinizi_girin>
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
227 Entering Passive Mode (192,0,2,1,195,80).
150 Here comes the directory listing.
drwxr-xr-x    2 ftp      ftp          4096 Oct 26  2023 pub
226 Directory send OK.
ftp> cd pub
250 Directory successfully changed.
ftp> get README.txt
227 Entering Passive Mode (192,0,2,1,195,81).
150 Opening BINARY mode data connection for README.txt (1024 bytes).
226 Transfer complete.
1024 bytes received in 0.01 secs (100.00 Kbytes/sec)
ftp> bye
221 Goodbye.
```

**Tekrar Hatırlatma:** Bu `ftp` istemcisi güvensizdir. Güvenli alternatifler için [SFTP](/internet-servisleri/ftp/sftp) bölümüne bakın veya `scp`/`rsync` kullanın.


# Zamanlanmış Görevler

Linux sistemlerinde, belirli komutların veya betiklerin (script) düzenli aralıklarla ya da belirli bir zamanda otomatik olarak çalıştırılması yaygın bir ihtiyaçtır. Bu bölümde, bu tür görevleri zamanlamak için kullanılan geleneksel araçlar ele alınacaktır.

İncelenecek konular şunlardır:

* **`cron`**: Tekrarlayan görevleri (örn. her saat başı, her gün belirli bir saatte, her ayın ilk günü vb.) zamanlamak için kullanılan standart Unix aracıdır. Kullanıcı bazında veya sistem genelinde tanımlanabilir.
  * [crontab](/zamanlanmis-goerevler/crontab)
* **`at`**: Bir komutun veya betiğin gelecekte **belirli bir zamanda sadece bir kez** çalıştırılmasını sağlar.

**Modern Alternatif: systemd Timers**

Modern systemd tabanlı sistemlerde, `cron` ve `at`'in işlevlerini daha esnek ve güçlü bir şekilde yerine getiren **systemd timer** birimleri (`.timer` uzantılı dosyalar) bulunmaktadır. Timer birimleri, başka bir systemd birimini (genellikle bir `.service` birimini) belirli zamanlarda veya olaylara bağlı olarak tetiklemek için kullanılır. Daha iyi loglama, kaynak yönetimi ve bağımlılık kontrolü gibi avantajlar sunarlar. Bu kitapta geleneksel `cron` ve `at` araçlarına odaklanılsa da, systemd timer'larının modern sistemlerde güçlü bir alternatif olduğunu belirtmek gerekir.


# crontab

`cron`, Unix benzeri işletim sistemlerinde belirli komutları veya betikleri (script) düzenli aralıklarla otomatik olarak çalıştırmak için kullanılan standart bir zamanlama daemon'ıdır (arka plan süreci). Çalıştırılacak görevler **crontab** (cron table) adı verilen dosyalarda tanımlanır.

## Crontab Dosyaları

Cron görevleri birkaç farklı yerde tanımlanabilir:

1. **Kullanıcı Crontab'ları:** Her kullanıcının kendi zamanlanmış görevlerini tanımlayabileceği özel bir crontab dosyası vardır. Bu dosyalar genellikle `/var/spool/cron/crontabs/` (veya benzeri bir dizinde) saklanır ancak doğrudan düzenlenmezler. Kullanıcılar kendi crontab'larını yönetmek için `crontab` komutunu kullanır. Bu crontab'daki komutlar, o kullanıcının yetkileriyle çalışır.
2. **Sistem Geneli Crontab (`/etc/crontab`):** Bu dosya, sistem genelindeki görevleri tanımlar. Kullanıcı crontab'larından farklı olarak, bu dosyada her satırda komutun hangi kullanıcı olarak çalıştırılacağı belirtilmelidir.
3. **`/etc/cron.d/` Dizini:** Sistem yöneticileri veya paketler, zamanlanmış görev tanımlarını bu dizine ayrı dosyalar halinde koyabilirler. Bu dosyalardaki format genellikle `/etc/crontab` ile aynıdır (kullanıcı belirtilmesi gerekir).
4. **Ön Tanımlı Zaman Aralıkları Dizini:** `/etc/cron.hourly/`, `/etc/cron.daily/`, `/etc/cron.weekly/`, `/etc/cron.monthly/` dizinlerine yerleştirilen çalıştırılabilir betikler, isimlerine uygun aralıklarla (`run-parts` komutu aracılığıyla, genellikle `/etc/crontab` içinden tetiklenerek) otomatik olarak çalıştırılır.

## Crontab Satır Formatı

Bir crontab dosyasındaki (kullanıcı crontab'ı veya `/etc/crontab`, `/etc/cron.d/` dosyaları) her satır bir zamanlanmış görevi temsil eder ve genellikle şu formatı takip eder:

```
# ┌───────────── dakika (0 - 59)
# │ ┌───────────── saat (0 - 23)
# │ │ ┌───────────── ayın günü (1 - 31)
# │ │ │ ┌───────────── ay (1 - 12) (veya Jan, Feb, Mar...)
# │ │ │ │ ┌───────────── haftanın günü (0 - 6) (Pazar=0 veya 7) (veya Sun, Mon...)
# │ │ │ │ │
# │ │ │ │ │
# * * * * * <kullanıcı_adı> <çalıştırılacak_komut>  <- Sadece /etc/crontab ve /etc/cron.d/ için kullanıcı adı gerekir
# * * * * * <çalıştırılacak_komut>              <- Kullanıcı crontab'ı için (crontab -e ile düzenlenen)
```

* İlk beş alan zamanlamayı belirler.
* `/etc/crontab` ve `/etc/cron.d/` dosyalarında altıncı alan komutun çalıştırılacağı kullanıcı adıdır. Kullanıcı crontab'larında bu alan bulunmaz, komut crontab sahibi kullanıcı olarak çalışır.
* Geri kalan kısım ise çalıştırılacak komut veya betiktir.

**Özel Karakterler:**

* **`*` (Yıldız):** İlgili alan için tüm olası değerleri ifade eder ("her"). Örneğin, dakika alanındaki `*` "her dakika" anlamına gelir.
* **`,` (Virgül):** Değer listelerini ayırmak için kullanılır. Örneğin, saat alanındaki `8,12,18` "saat 8, 12 ve 18'de" anlamına gelir.
* **`-` (Tire):** Değer aralıklarını belirtmek için kullanılır. Örneğin, haftanın günü alanındaki `1-5` "Pazartesiden Cumaya kadar" (Pazartesi=1) anlamına gelir.
* **`/` (Bölü):** Adım değerlerini belirtmek için kullanılır. Örneğin, dakika alanındaki `*/15` "her 15 dakikada bir" (0, 15, 30, 45) anlamına gelir. Saat alanındaki `8-18/2` "saat 8'den 18'e kadar her 2 saatte bir" (8, 10, 12, 14, 16, 18) anlamına gelir.

**Özel Zaman Dizgeleri:** Bazı `cron` implementasyonları, yaygın zamanlamalar için özel dizgeleri destekler:

* `@reboot`: Sistem başlangıcında bir kez çalıştırılır.
* `@yearly` veya `@annually`: Yılda bir kez çalıştırılır (`0 0 1 1 *`).
* `@monthly`: Ayda bir kez çalıştırılır (`0 0 1 * *`).
* `@weekly`: Haftada bir kez çalıştırılır (`0 0 * * 0`).
* `@daily` veya `@midnight`: Günde bir kez çalıştırılır (`0 0 * * *`).
* `@hourly`: Saatte bir kez çalıştırılır (`0 * * * *`).

**Örnek Crontab Satırları:**

```bash
# Her gece 02:30'da yedekleme betiğini çalıştır
30 2 * * * /usr/local/bin/yedekle.sh

# Her Pazartesi sabah 05:00'te sistemi güncelle (apt örneği)
0 5 * * 1 apt update && apt upgrade -y

# Her 15 dakikada bir disk kullanımını logla
*/15 * * * * df -h >> /var/log/disk_kullanimi.log

# Her ayın 1'inde saat 04:05'te root olarak bir betik çalıştır (/etc/cron.d/ veya /etc/crontab içinde)
5 4 1 * * root /opt/aylik_rapor.sh

# Sistem her başladığında bir kontrol yap
@reboot /usr/local/bin/baslangic_kontrolu.sh
```

## `crontab` Komutu

Kullanıcılar kendi crontab dosyalarını yönetmek için `crontab` komutunu kullanır:

* **`crontab -e`**: Mevcut kullanıcının crontab dosyasını düzenlemek için varsayılan metin düzenleyiciyi açar. İlk kez çalıştırıldığında genellikle hangi düzenleyiciyi kullanmak istediğinizi sorar. Dosyayı kaydedip çıktığınızda yeni zamanlanmış görevler aktif olur.
* **`crontab -l`**: Mevcut kullanıcının crontab dosyasının içeriğini listeler.
* **`crontab -r`**: Mevcut kullanıcının crontab dosyasını **komple siler**. **Dikkatli kullanılmalıdır!** Yanlışlıkla silmeye karşı genellikle onay istemez.
* **`crontab -u <kullanıcı_adı> -e|-l|-r`**: (Sadece root tarafından) Belirtilen kullanıcının crontab dosyasını yönetmek için kullanılır.

## Ortam Değişkenleri ve Çıktı Yönetimi

* **Ortam:** Cron görevleri, normal bir kullanıcı kabuğuna göre çok daha kısıtlı bir ortam değişkeni seti ile çalışır. Özellikle `PATH` değişkeni sınırlı olabilir. Bu nedenle, cron görevlerinde çalıştırılan komutların veya betiklerin içinde kullanılan diğer komutların tam yollarını belirtmek (örn. `/usr/bin/python3` yerine sadece `python3` yazmamak) genellikle daha güvenilirdir. Crontab dosyasının başına `PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin` gibi bir satır ekleyerek PATH'i ayarlamak da mümkündür.
* **Çıktı:** Varsayılan olarak, bir cron görevinin standart çıktısı (stdout) veya standart hatası (stderr) olursa, bu çıktı crontab sahibi kullanıcıya e-posta olarak gönderilir (eğer sistemde bir posta transfer ajanı - MTA - yapılandırılmışsa).
  * Çıktıyı bir dosyaya yönlendirmek için standart kabuk yönlendirmeleri kullanılır:

    ```bash
    * * * * * /path/to/command > /var/log/myjob.log 2>&1 
    ```

    (`>` üzerine yazar, `>>` sona ekler, `2>&1` stderr'i stdout'a yönlendirir).
  * Tüm çıktıyı engellemek için `/dev/null`'a yönlendirilebilir:

    ```bash
    * * * * * /path/to/command > /dev/null 2>&1
    ```
  * E-postanın gönderileceği adresi değiştirmek için crontab dosyasının başına `MAILTO` değişkeni eklenebilir:

    ```bash
    MAILTO="admin@example.com"
    * * * * * /path/to/command 
    ```
  * E-posta gönderimini tamamen engellemek için `MAILTO` boş bırakılabilir:

    ```bash
    MAILTO=""
    * * * * * /path/to/command 
    ```

`cron`, sistem bakımı, yedekleme, raporlama gibi birçok görevi otomatikleştirmek için vazgeçilmez bir araçtır.


# at

`cron` tekrarlayan görevler için kullanılırken, **`at`** komutu belirli komutların veya betiklerin gelecekte **belirli bir zamanda sadece bir kez** çalıştırılmasını sağlamak için kullanılır.

## `atd` Servisi

`at` komutu ile zamanlanan görevlerin çalıştırılabilmesi için sistemde `atd` (at daemon) servisinin çalışıyor olması gerekir. Çoğu dağıtımda varsayılan olarak kurulu ve etkin olabilir, ancak kontrol etmek gerekebilir:

```bash
# Servisin durumunu kontrol et
sudo systemctl status atd

# Gerekirse başlat ve etkinleştir
# sudo systemctl start atd
# sudo systemctl enable atd
```

## Görev Zamanlama

`at` komutuna çalıştırılacak zaman parametre olarak verilir. Zaman belirtildikten sonra, `at` komutu standart girdiden çalıştırılacak komutları okumaya başlar. Komutları girdikten sonra, genellikle yeni bir satırda `Ctrl+D` tuş kombinasyonuna basarak girdi sonlandırılır ve görev zamanlanır.

**Zaman Belirtme Formatları:**

`at` komutu oldukça esnek bir zaman belirtme formatını anlar:

* **Kesin Zaman:**
  * `HH:MM`: Bugün belirtilen saatte (eğer saat geçmişse yarın). Örn: `at 14:30`
  * `HH:MM YYYY-MM-DD`: Belirtilen tarih ve saatte. Örn: `at 09:00 2025-12-25`
  * `noon` (öğlen), `midnight` (gece yarısı), `teatime` (16:00) gibi anahtar kelimeler.
  * `HH:MM <gün_adı>`: Gelecek belirtilen günde. Örn: `at 11:00 Sunday`
* **Göreceli Zaman:**
  * `now + <sayı> <birim>`: Şu andan itibaren belirtilen süre sonra. Birimler: `minutes`, `hours`, `days`, `weeks`. Örn: `at now + 1 hour`, `at now + 30 minutes`
  * `HH:MM tomorrow`: Yarın belirtilen saatte.
  * `HH:MM next <birim>`: Gelecek hafta/ay/yıl belirtilen saatte. Örn: `at 10:00 next week`

**Örnek Kullanım (İnteraktif):**

```bash
$ at 10:30 tomorrow 
warning: commands will be executed using /bin/sh
at> echo "Bu mesaj yarın sabah 10:30'da loglanacak" >> /home/user/at_test.log
at> echo "İkinci komut" >> /home/user/at_test.log
at> <Ctrl+D>  # Girdiyi bitir
job 1 at Mon Mar 31 10:30:00 2025 
```

Bu komutlar, belirtilen zamanda (`Mon Mar 31 10:30:00 2025`) `/bin/sh` kabuğu kullanılarak çalıştırılacaktır.

**Örnek Kullanım (Pipe ile):**

Tek bir komutu zamanlamak için `echo` ve pipe kullanılabilir:

```bash
echo "/usr/local/bin/gece_yarisi_betigi.sh" | at midnight
```

**Örnek Kullanım (Dosyadan):**

Çalıştırılacak komutları içeren bir dosyayı `-f` seçeneği ile belirtebilirsiniz:

```bash
# komutlar.txt dosyasının içeriği:
# echo "Dosyadan gelen görev"
# date

at -f komutlar.txt now + 5 minutes 
```

## Zamanlanmış Görevleri Yönetme

* **Görevleri Listeleme (`atq` veya `at -l`):**\
  Kullanıcının bekleyen `at` görevlerini listeler. Her görevin bir iş numarası (job ID) vardır.

  ```bash
  $ atq
  1   Mon Mar 31 10:30:00 2025 a user
  2   Tue Apr  1 00:00:00 2025 a user
  ```
* **Görevi Silme (`atrm` veya `at -d`):**\
  Belirtilen iş numarasına sahip görevi kuyruktan kaldırır.

  ```bash
  atrm 1
  # veya
  at -d 2 
  ```
* **Görevin İçeriğini Görme (`at -c`):**\
  Belirtilen iş numarasına sahip görevin çalıştıracağı komutları (ve ortam değişkenlerini) gösterir.

  ```bash
  at -c 1 
  ```

## Erişim Kontrolü

Hangi kullanıcıların `at` komutunu kullanabileceği `/etc/at.allow` ve `/etc/at.deny` dosyaları ile kontrol edilebilir:

* Eğer `/etc/at.allow` dosyası varsa, sadece bu dosyada listelenen kullanıcılar `at` kullanabilir.
* Eğer `/etc/at.allow` yoksa ama `/etc/at.deny` varsa, bu dosyada listelenen kullanıcılar *dışındaki* herkes `at` kullanabilir.
* Eğer iki dosya da yoksa, genellikle sadece root kullanıcısı `at` kullanabilir (dağıtıma göre değişebilir).

`at` komutu, tek seferlik görevleri basitçe zamanlamak için kullanışlı bir araçtır. Tekrarlayan görevler için `cron` veya systemd timer'ları daha uygundur.


# Veritabanı

Veritabanları, yapılandırılmış bilgileri (verileri) depolamak, yönetmek, sorgulamak ve güncellemek için kullanılan organize sistemlerdir. Modern uygulamaların ve web sitelerinin temel taşlarından biridir.

## Neden Veritabanı Kullanılır?

* **Veri Kalıcılığı:** Uygulama kapansa veya sistem yeniden başlasa bile verilerin saklanmasını sağlar.
* **Veri Bütünlüğü:** Belirlenen kurallar (kısıtlamalar, veri tipleri) aracılığıyla verinin doğruluğunu ve tutarlılığını korur.
* **Verimli Erişim:** Büyük miktarda veri içinden istenen bilgiye hızlı ve verimli bir şekilde erişmek için indeksleme ve sorgulama mekanizmaları sunar.
* **Eşzamanlılık Kontrolü:** Birden fazla kullanıcının veya uygulamanın aynı anda veritabanına güvenli bir şekilde erişmesini ve değişiklik yapmasını yönetir.
* **Güvenlik:** Kullanıcı yetkilendirme ve erişim kontrolü mekanizmaları ile verilere kimin erişebileceğini ve hangi işlemleri yapabileceğini sınırlar.
* **Yedekleme ve Kurtarma:** Veri kaybına karşı yedekleme ve kurtarma mekanizmaları sunar.

## Veritabanı Türleri

Birçok farklı veritabanı modeli bulunmaktadır, ancak en yaygın olanlardan bazıları şunlardır:

* **İlişkisel Veritabanları (Relational Databases - RDBMS):** Verileri satırlar ve sütunlardan oluşan tablolarda saklar. Tablolar arasında ilişkiler kurulabilir. SQL (Structured Query Language) sorgulama dili kullanılır. En yaygın kullanılan türdür. Örnekler: MySQL, MariaDB, PostgreSQL, SQLite, Oracle Database, Microsoft SQL Server.
* **NoSQL Veritabanları:** İlişkisel modelin kısıtlamalarına alternatif olarak geliştirilmişlerdir. Farklı veri modelleri kullanırlar:
  * **Belge Tabanlı (Document):** Verileri JSON/BSON benzeri belgelerde saklar (örn. MongoDB, Couchbase).
  * **Anahtar-Değer (Key-Value):** Basit anahtar-değer çiftleri olarak saklar (örn. Redis, Memcached).
  * **Sütun Ailesi (Column-Family):** Büyük veri setleri için optimize edilmiştir (örn. Cassandra, HBase).
  * **Grafik (Graph):** Veriler arasındaki ilişkileri ön plana çıkarır (örn. Neo4j, ArangoDB).

## İlişkisel Veritabanı Nedir?

İlişkisel veritabanları, verileri önceden tanımlanmış bir şemaya göre yapılandırılmış tablolarda saklar.

* **Tablolar (Tables):** Belirli bir türdeki verileri tutar (örn. 'kullanicilar', 'urunler', 'siparisler').
* **Satırlar (Rows/Records):** Tablodaki her bir kaydı temsil eder (örn. belirli bir kullanıcı, belirli bir ürün).
* **Sütunlar (Columns/Fields/Attributes):** Bir kaydın belirli bir özelliğini temsil eder (örn. 'kullanici\_adi', 'email', 'urun\_fiyati'). Her sütunun belirli bir veri tipi vardır (örn. INTEGER, VARCHAR, DATE).
* **Anahtarlar (Keys):**
  * **Birincil Anahtar (Primary Key):** Tablodaki her satırı benzersiz şekilde tanımlayan bir veya daha fazla sütun.
  * **Yabancı Anahtar (Foreign Key):** Bir tablodaki sütunun, başka bir tablonun birincil anahtarına başvurarak tablolar arasında ilişki kurmasını sağlar.
* **SQL (Structured Query Language):** İlişkisel veritabanlarında veri tanımlamak (CREATE TABLE), veri işlemek (INSERT, UPDATE, DELETE) ve veri sorgulamak (SELECT) için kullanılan standart dildir.

Bu kitapta, Linux ortamında yaygın olarak kullanılan ilişkisel veritabanlarından **MySQL** (ve onun topluluk tarafından geliştirilen popüler bir çatalı olan **MariaDB**) üzerine odaklanılacaktır. Ayrıca, güçlü ve açık kaynaklı bir alternatif olan **PostgreSQL** de sıklıkla tercih edilen bir seçenektir.

* [MySQL / MariaDB](/veritabani/mysql)


# MySQL

MySQL, dünyanın en popüler açık kaynaklı ilişkisel veritabanı yönetim sistemlerinden (RDBMS) biridir. Özellikle web uygulamalarıyla birlikte yaygın olarak kullanılır. Oracle Corporation tarafından geliştirilmektedir.

MariaDB, MySQL'in orijinal geliştiricileri tarafından oluşturulan, topluluk tarafından geliştirilen bir çatalıdır (fork). MySQL ile yüksek düzeyde uyumluluk sunmayı hedeflerken, bazı ek özellikler ve farklı depolama motorları da içerir. Birçok Linux dağıtımı, Oracle'ın MySQL'i satın almasından sonra varsayılan "MySQL" paketi olarak MariaDB'yi sunmaya başlamıştır.

Bu bölümde, hem MySQL hem de MariaDB için geçerli olan temel kavramlar, kurulum, yönetim ve kullanım konuları ele alınacaktır. Komutlar ve yapılandırma genellikle iki sistem arasında çok benzerdir veya aynıdır.

**İncelenecek Konular:**

* [MySQL/MariaDB Kurulumu](/veritabani/mysql/mysql-kurulumu): Paket yöneticileri ile kurulum ve ilk güvenlik ayarları.
* [MySQL/MariaDB Servisini Çalıştırmak](/veritabani/mysql/mysql-servisini-calistirmak): `systemctl` ile servis yönetimi.
* [Veritabanı ve Tablo Oluşturmak](/veritabani/mysql/veritabani-ve-tablo-olusturmak): Temel DDL (Data Definition Language) komutları (`CREATE DATABASE`, `CREATE TABLE`).
* [SQL Tablosuna Veri Eklemek](/veritabani/mysql/sql-tablosuna-veri-eklemek): Temel DML (Data Manipulation Language) komutu (`INSERT INTO`).
* [Temel SQL Sorgularına Giriş](/veritabani/mysql/temel-sql-sorgularina-giris): `SELECT` komutu ile veri sorgulama.
* [mysqldump ile Yedekleme](/veritabani/mysql/mysqldump-ile-yedekleme): Veritabanlarını yedeklemek için `mysqldump` kullanımı.
* [Yedekleri İçeri Alma](/veritabani/mysql/yedekleri-iceri-alma): `mysql` istemcisi ile yedekleri geri yükleme.
* [Replikasyon Teknikleri](/veritabani/mysql/replikasyon-teknikleri): Veritabanı kopyalama (master-slave) yöntemlerine genel bakış.


# MySQL Kurulumu

MySQL veya onun popüler topluluk çatalı olan MariaDB'yi Linux sisteminize kurmak için genellikle dağıtımınızın paket yöneticisini kullanabilirsiniz. Çoğu modern dağıtım (Debian, Ubuntu, Fedora, RHEL 8+, CentOS Stream 8+, AlmaLinux, Rocky Linux) varsayılan olarak MariaDB'yi sunar. Oracle'ın resmi MySQL Community Server sürümünü kurmak isterseniz, genellikle önce Oracle'ın kendi yazılım deposunu sisteme eklemeniz gerekir.

Bu bölümde her iki veritabanı sunucusunun yaygın dağıtımlardaki temel kurulum adımları ve ilk güvenlik yapılandırması ele alınacaktır.

## 1. MariaDB Kurulumu (Yaygın Dağıtım Depolarından)

MariaDB genellikle dağıtımın ana depolarında bulunur ve kurulumu basittir.

* **RHEL Tabanlı (dnf):**

  ```bash
  # MariaDB sunucusunu ve istemcisini kur
  sudo dnf install mariadb-server -y

  # Servisi başlat ve sistem başlangıcında etkinleştir
  sudo systemctl start mariadb
  sudo systemctl enable mariadb

  # İlk güvenlik ayarlarını yap (root şifresi belirle, test db kaldır vb.)
  sudo mariadb-secure-installation 
  ```
* **Debian Tabanlı (apt):**

  ```bash
  # MariaDB sunucusunu ve istemcisini kur
  sudo apt update
  sudo apt install mariadb-server -y

  # Servisin otomatik başlamış ve etkinleştirilmiş olması gerekir, kontrol et:
  # sudo systemctl status mariadb

  # İlk güvenlik ayarlarını yap
  sudo mariadb-secure-installation
  ```

**`mariadb-secure-installation` Betiği:**\
Bu betik, kurulumdan sonra çalıştırılması **şiddetle tavsiye edilen** interaktif bir güvenlik yapılandırma aracıdır. Size aşağıdaki adımlarda yol gösterir:

* Mevcut root şifresini sorma (ilk kurulumda genellikle boştur, Enter ile geçilir).
* Root kullanıcısı için bir şifre belirleme veya Unix soket kimlik doğrulamasını kullanma seçeneği sunma.
* Anonim kullanıcıları kaldırma.
* Root kullanıcısının uzaktan bağlanmasını engelleme (önerilir).
* Test veritabanını ve erişimini kaldırma.
* Yetki tablolarını yeniden yükleme.

Genellikle tüm sorulara 'Y' (Evet) yanıtı vermek iyi bir başlangıç noktasıdır.

## 2. MySQL Community Server Kurulumu (Oracle Deposundan)

Oracle'ın resmi MySQL sürümünü kurmak için genellikle önce MySQL APT veya YUM deposunu sisteme eklemeniz gerekir.

1. **MySQL Depo RPM/DEB Paketini İndirme:**\
   MySQL Community İndirme sayfasından (`https://dev.mysql.com/downloads/repo/`) sisteminize uygun depo yapılandırma paketini (.rpm veya .deb) indirin. Örneğin:

   ```bash
   # RHEL/CentOS/Fedora için (örnek, güncel sürümü kontrol edin)
   wget https://dev.mysql.com/get/mysql80-community-release-el9-1.noarch.rpm 

   # Debian/Ubuntu için (örnek, güncel sürümü kontrol edin)
   wget https://dev.mysql.com/get/mysql-apt-config_0.8.29-1_all.deb
   ```
2. **Depo Paketini Kurma:**

   ```bash
   # RHEL/CentOS/Fedora
   sudo rpm -ivh mysql80-community-release-el9-1.noarch.rpm

   # Debian/Ubuntu
   sudo dpkg -i mysql-apt-config_0.8.29-1_all.deb
   # (Kurulum sırasında hangi MySQL sürümünü istediğinizi soran bir ekran çıkabilir)
   sudo apt update # Depo eklendikten sonra listeyi güncelle
   ```
3. **MySQL Server Kurulumu:**

   ```bash
   # RHEL/CentOS/Fedora
   sudo dnf install mysql-community-server -y

   # Debian/Ubuntu
   sudo apt install mysql-server -y 
   # (Kurulum sırasında root şifresi belirlemeniz istenebilir)
   ```
4. **Servisi Başlatma ve Etkinleştirme:**

   ```bash
   sudo systemctl start mysqld # Servis adı genellikle mysqld'dir
   sudo systemctl enable mysqld
   ```
5. **İlk Güvenlik Ayarları (`mysql_secure_installation`):**\
   MySQL kurulumundan sonra bu betiği çalıştırmak **çok önemlidir**.

   ```bash
   sudo mysql_secure_installation
   ```

   Bu betik, `mariadb-secure-installation`'a benzer şekilde çalışır:

   * Validate Password Component'i etkinleştirme seçeneği sunar (güçlü şifre politikası).
   * Root şifresini belirlemenizi veya değiştirmenizi ister. (MySQL 5.7+ sürümlerinde kurulum sırasında geçici bir şifre `/var/log/mysqld.log` dosyasına yazılmış olabilir, ilk girişte bu sorulabilir).
   * Anonim kullanıcıları kaldırır.
   * Uzaktan root girişini engeller.
   * Test veritabanını kaldırır.
   * Yetki tablolarını yeniden yükler.

Kurulum tamamlandıktan ve güvenlik ayarları yapıldıktan sonra, veritabanı sunucunuz kullanıma hazırdır. Bir sonraki adım genellikle [servisi yönetmek](/veritabani/mysql/mysql-servisini-calistirmak) ve [veritabanları/tablolar oluşturmaktır](/veritabani/mysql/veritabani-ve-tablo-olusturmak).


# MySQL Servisini Çalıştırmak

MySQL veya MariaDB sunucusu kurulduktan sonra, bir sistem servisi olarak çalışır. Modern Linux dağıtımlarında bu servis `systemd` tarafından yönetilir. Servis adı genellikle `mysqld` (MySQL için) veya `mariadb` (MariaDB için)'dir.

Servisleri yönetmek için `systemctl` komutu kullanılır (`sudo` yetkisi gereklidir):

**Servis Durumunu Kontrol Etme:**

```bash
sudo systemctl status mariadb 
# veya
sudo systemctl status mysqld 
```

Bu komut, servisin aktif (`active (running)`) olup olmadığını, ne zamandır çalıştığını ve son log mesajlarını gösterir.

Örnek Çıktı (MariaDB):

```
● mariadb.service - MariaDB 10.5.15 database server
     Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2023-10-27 10:30:00 +03; 5min ago
       Docs: man:mariadbd(8)
             https://mariadb.com/kb/en/library/systemd/
   Main PID: 1234 (mariadbd)
     Status: "Taking your SQL requests now..."
      Tasks: 15 (limit: 4617)
     Memory: 100.0M
        CPU: 500ms
     CGroup: /system.slice/mariadb.service
             └─1234 /usr/sbin/mariadbd
...
```

**Servisi Başlatma:**\
Eğer servis çalışmıyorsa, başlatmak için:

```bash
sudo systemctl start mariadb 
# veya
sudo systemctl start mysqld
```

**Servisi Durdurma:**

```bash
sudo systemctl stop mariadb 
# veya
sudo systemctl stop mysqld
```

**Servisi Yeniden Başlatma:**\
Yapılandırma değişikliklerinden sonra veya sorun giderme amacıyla:

```bash
sudo systemctl restart mariadb 
# veya
sudo systemctl restart mysqld
```

**Sistem Başlangıcında Etkinleştirme/Devre Dışı Bırakma:**\
Servisin sistem açıldığında otomatik olarak başlamasını sağlamak için:

```bash
sudo systemctl enable mariadb 
# veya
sudo systemctl enable mysqld
```

Otomatik başlamasını engellemek için:

```bash
sudo systemctl disable mariadb 
# veya
sudo systemctl disable mysqld
```

## `mysqladmin` ile Durum Kontrolü

`mysqladmin` komutu, çalışan bir MySQL/MariaDB sunucusu hakkında bilgi almak ve bazı temel yönetim görevlerini yapmak için kullanılan bir istemci aracıdır. Bağlantı için kullanıcı adı ve şifre gerektirir.

Sunucu sürümünü ve durumunu kontrol etmek için:

```bash
mysqladmin -u root -p version status
```

Komut sizden root kullanıcısının şifresini isteyecektir.

Örnek Çıktı:

```
mysqladmin  Ver 9.1 Distrib 10.5.15-MariaDB, for debian-linux-gnu on x86_64
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Server version          10.5.15-MariaDB-0+deb11u1
Protocol version        10
Connection              Localhost via UNIX socket
UNIX socket             /run/mysqld/mysqld.sock
Uptime:                 10 min 5 sec

Threads: 7  Questions: 123  Slow queries: 0  Opens: 34  Flush tables: 1  Open tables: 27  Queries per second avg: 0.203
Uptime: 605  Threads: 7  Questions: 123  Slow queries: 0  Opens: 34  Flush tables: 1  Open tables: 27  Queries per second avg: 0.203
```

## Güvenlik Ayarları

Veritabanı sunucusu kurulduktan sonra çalışır durumda olsa bile, canlı ortamlarda kullanmadan önce temel güvenlik ayarlarının yapılması **çok önemlidir**. Bu işlem genellikle kurulum bölümünde bahsedilen `mariadb-secure-installation` veya `mysql_secure_installation` betikleri aracılığıyla yapılır. Bu betikler root şifresini ayarlamanıza, anonim kullanıcıları kaldırmanıza, uzaktan root girişini engellemenize ve test veritabanını kaldırmanıza yardımcı olur. Bu adımları atlamadığınızdan emin olun.


# Veritabanı ve Tablo oluşturmak

MySQL veya MariaDB sunucusundaki veritabanlarını ve tabloları yönetmek için komut satırı istemcisi (`mysql` veya `mariadb`) kullanılır. Grafiksel araçlar da mevcut olsa da, temel işlemleri komut satırından yapmak önemlidir.

**MySQL/MariaDB Kabuğuna Bağlanma:**

Genellikle `root` kullanıcısı ile bağlanılır. Bağlantı yöntemi, kurulum sırasında belirlenen kimlik doğrulama yöntemine göre değişir:

* **Şifre ile:**

  ```bash
  mysql -u root -p 
  ```

  Bu komut `root` kullanıcısının şifresini soracaktır. `-u` kullanıcı adını, `-p` şifre sorulacağını belirtir.
* **Unix Soket Kimlik Doğrulaması ile (Yaygın):**\
  Modern kurulumlarda `root` kullanıcısı genellikle şifre yerine sistemin `root` kullanıcısı ile eşleştirilir (örn. `auth_socket` veya `unix_socket` eklentisi ile). Bu durumda `sudo` kullanarak şifresiz bağlanılabilir:

  ```bash
  sudo mysql 
  # veya sudo mariadb
  ```

Başarıyla bağlandıktan sonra `mysql>` veya `MariaDB [(none)]>` gibi bir istem (prompt) görürsünüz.

```bash
[celep@veriteknik ~]$ mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 21
Server version: 5.6.39 MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
```

Şimdi varolan veritabanlarını listelemek için `SHOW DATABASES;` komutunu kullanalım.

> **Not:** MySQL/MariaDB kabuğundaki çoğu SQL komutu noktalı virgül (`;`) ile bitirilmelidir. `\g` de alternatif olarak kullanılabilir. `help;` veya `\h` komutu yardım bilgilerini gösterir. `exit` veya `quit` ile kabuktan çıkılır.

```bash
mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)
```

Şu an MySQL'in içinde varsayılan sistem veritabanlarını görüyoruz (`information_schema`, `mysql`, `performance_schema`, `sys`). Kendi veritabanımızı oluşturalım.

**Veritabanı Oluşturma (`CREATE DATABASE`):**

`company` adında yeni bir veritabanı oluşturalım. Türkçe karakterleri ve modern Unicode desteğini düzgün sağlamak için genellikle `utf8mb4` karakter seti ve uygun bir collation (örn. `utf8mb4_general_ci` veya `utf8mb4_unicode_ci`) belirtmek iyi bir pratiktir.

```sql
CREATE DATABASE company 
CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci;
```

```
Query OK, 1 row affected (0.00 sec)
```

Komut başarıyla çalıştı. `SHOW DATABASES;` komutuyla `company` veritabanının eklendiğini görebilirsiniz.

**Veritabanını Seçme (`USE`):**

İşlemlerimizi bu veritabanı üzerinde yapmak için onu seçmemiz gerekir:

```sql
USE company;
```

```
mysql> USE company;
Database changed
```

Veritabanımıza bağlandık. İçerisindeki tabloları görüntülemek için SHOW TABLES; komutunu çalıştıralım.

```bash
mysql> SHOW TABLES;
Empty set (0.00 sec)
```

Gördüğünüz gibi içinde herhangi bir tablo yok. Şimdi `member` adında bir tablo oluşturalım.

**Tablo Oluşturma (`CREATE TABLE`):**

`CREATE TABLE` komutu ile tablonun adı ve içereceği sütunlar (kolonlar) tanımlanır. Her sütun için bir ad, bir veri tipi ve isteğe bağlı kısıtlamalar (constraints) belirtilir.

```sql
CREATE TABLE member (
    id INT NOT NULL AUTO_INCREMENT,         -- Otomatik artan tam sayı ID
    first_name VARCHAR(50) NOT NULL,        -- İsim (Boş olamaz)
    last_name VARCHAR(50) NOT NULL,         -- Soyisim (Boş olamaz)
    email VARCHAR(100) UNIQUE,              -- E-posta (Benzersiz olmalı)
    birthday DATE NULL,                     -- Doğum tarihi (Boş olabilir)
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Kayıt oluşturma zamanı (varsayılan: şu an)
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- Kayıt güncelleme zamanı
    PRIMARY KEY (id)                        -- 'id' sütununu birincil anahtar yap
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 
```

**Açıklamalar:**

* `id INT NOT NULL AUTO_INCREMENT`: `id` adında, tam sayı (`INT`), boş olamayan (`NOT NULL`), her yeni kayıtta otomatik olarak artan (`AUTO_INCREMENT`) bir sütun. Genellikle birincil anahtar olarak kullanılır.
* `first_name VARCHAR(50) NOT NULL`: En fazla 50 karakter uzunluğunda metin (`VARCHAR`), boş olamaz.
* `email VARCHAR(100) UNIQUE`: En fazla 100 karakter uzunluğunda metin, bu sütundaki değerler benzersiz (`UNIQUE`) olmalıdır (aynı e-posta iki kez girilemez).
* `birthday DATE NULL`: Tarih (`YYYY-MM-DD` formatında), boş (`NULL`) olabilir.
* `created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP`: Zaman damgası (`YYYY-MM-DD HH:MM:SS` formatında). Kayıt eklendiğinde varsayılan olarak o anki zaman damgasını alır (`DEFAULT CURRENT_TIMESTAMP`).
* `updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`: Zaman damgası. Kayıt eklendiğinde varsayılan olarak o anki zamanı alır ve kayıt her güncellendiğinde otomatik olarak o anki zaman damgasıyla güncellenir (`ON UPDATE CURRENT_TIMESTAMP`).
* `PRIMARY KEY (id)`: `id` sütununu tablonun birincil anahtarı olarak tanımlar. Birincil anahtar, tablodaki her satırı benzersiz şekilde tanımlar ve genellikle `NOT NULL` olmalıdır.
* `ENGINE=InnoDB`: Kullanılacak depolama motorunu belirtir. `InnoDB` varsayılan ve en yaygın kullanılan motordur; ACID uyumluluğu (transactions), satır seviyesinde kilitleme ve yabancı anahtar (foreign key) desteği sunar. Eski `MyISAM` motoru genellikle özel durumlar dışında tercih edilmez.
* `DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`: Tablo için varsayılan karakter setini ve karşılaştırma (collation) kurallarını belirler. `utf8mb4` modern Unicode karakterlerini (emoji dahil) destekler ve genellikle önerilir.

```
Query OK, 0 rows affected (0.03 sec)
```

Tablomuz başarıyla oluşturuldu. `SHOW TABLES;` komutu artık `member` tablosunu listelemelidir.

**Tablo Yapısını Görme (`DESCRIBE` veya `SHOW COLUMNS`):**

Oluşturulan tablonun sütunlarını ve özelliklerini görmek için `DESCRIBE` veya `SHOW COLUMNS FROM` komutları kullanılır:

```sql
DESCRIBE member;
-- veya
SHOW COLUMNS FROM member;
```

```
mysql> DESCRIBE member;
+------------+--------------+------+-----+---------------------+-------------------------------+
| Field      | Type         | Null | Key | Default             | Extra                         |
+------------+--------------+------+-----+---------------------+-------------------------------+
| id         | int          | NO   | PRI | NULL                | auto_increment                |
| first_name | varchar(50)  | NO   |     | NULL                |                               |
| last_name  | varchar(50)  | NO   |     | NULL                |                               |
| email      | varchar(100) | YES  | UNI | NULL                |                               |
| birthday   | date         | YES  |     | NULL                |                               |
| created_at | timestamp    | YES  |     | CURRENT_TIMESTAMP   |                               |
| updated_at | timestamp    | YES  |     | CURRENT_TIMESTAMP   | on update CURRENT_TIMESTAMP |
+------------+--------------+------+-----+---------------------+-------------------------------+
7 rows in set (0.00 sec)

```

Sıradaki bölümde tablomuza veri ekleyeceğiz.


# SQL Tablosuna Veri Eklemek

Bundan önceki bölümde tablomuzu oluşturmuştuk.

```
mysql> SHOW TABLES;
+-------------------+
| Tables_in_company |
+-------------------+
| member            |
+-------------------+
1 row in set (0.00 sec)
```

Şimdi bu tabloya `INSERT INTO` komutu ile veri ekleyelim.

**Tek Satır Ekleme:**

`AUTO_INCREMENT` ve `DEFAULT` değerleri olan sütunları (bizim örneğimizde `id`, `created_at`, `updated_at`) belirtmemize gerek yoktur, veritabanı bunları otomatik olarak halleder. Sadece değer girmek istediğimiz sütunları belirtmemiz yeterlidir:

```sql
INSERT INTO member (first_name, last_name, email, birthday) 
VALUES ('Yaşar', 'Celep', 'celep@veriteknik.com', '1996-12-23'); 
```

Başarılı olursa şöyle bir çıktı alınır:

```
Query OK, 1 row affected (0.02 sec)
```

**Birden Fazla Satır Ekleme:**

Tek bir `INSERT INTO` komutu ile birden fazla satır eklemek için `VALUES` kısmından sonra değer gruplarını virgülle ayırarak listeleyebilirsiniz:

```sql
INSERT INTO member (first_name, last_name, email, birthday) VALUES 
('Ahmet', 'Yılmaz', 'ahmet@example.com', '1990-05-15'),
('Ayşe', 'Kaya', 'ayse.kaya@example.net', NULL), -- Doğum tarihi boş olabilir
('Mehmet', 'Demir', 'mehmet@example.org', '1985-01-30');
```

```
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0
```

**Veriyi Kontrol Etme (`SELECT`):**

Eklenen verileri görmek için `SELECT * FROM <tablo_adı>;` komutunu kullanabiliriz. `*` sembolü "tüm sütunları" getir anlamına gelir.

```sql
SELECT * FROM member;
```

Örnek Çıktı:

```
+----+------------+-----------+----------------------+------------+---------------------+---------------------+
| id | first_name | last_name | email                | birthday   | created_at          | updated_at          |
+----+------------+-----------+----------------------+------------+---------------------+---------------------+
|  1 | Yaşar      | Celep     | celep@veriteknik.com | 1996-12-23 | 2025-03-28 06:18:00 | 2025-03-28 06:18:00 |
|  2 | Ahmet      | Yılmaz    | ahmet@example.com    | 1990-05-15 | 2025-03-28 06:18:30 | 2025-03-28 06:18:30 |
|  3 | Ayşe       | Kaya      | ayse.kaya@example.net| NULL       | 2025-03-28 06:18:30 | 2025-03-28 06:18:30 |
|  4 | Mehmet     | Demir     | mehmet@example.org   | 1985-01-30 | 2025-03-28 06:18:30 | 2025-03-28 06:18:30 |
+----+------------+-----------+----------------------+------------+---------------------+---------------------+
4 rows in set (0.00 sec)
```

Gördüğünüz gibi `id` sütunu otomatik olarak arttı ve `created_at`/`updated_at` sütunları otomatik olarak o anki zaman damgasıyla dolduruldu. `birthday` sütununa `NULL` değer girilebildi.


# Temel SQL Sorgularına Giriş

Veritabanına veri ekledikten sonra, bu veriyi geri almak, filtrelemek, sıralamak ve işlemek için SQL'in **`SELECT`** komutu kullanılır. `SELECT` komutu, SQL'in en temel ve en sık kullanılan komutlarından biridir.

Bu bölümde, `SELECT` komutunun temel kullanımı ve yaygın kullanılan bazı yan tümceleri (clauses) ele alınacaktır:

* Belirli sütunları seçme.
* Tüm sütunları seçme (`*`).
* Satırları filtreleme (`WHERE`).
* Sonuçları sıralama (`ORDER BY`).
* Döndürülecek satır sayısını sınırlama (`LIMIT`).

Detaylı örnekler için aşağıdaki bölüme bakınız:

* [Birinci Bölüm](/veritabani/mysql/temel-sql-sorgularina-giris/birinci-boeluem)


# Birinci bölüm

`SELECT` komutu, veritabanı tablolarından veri çekmek için kullanılır. En temel SQL komutlarından biridir ve çeşitli yan tümceler (clauses) ile birlikte kullanılarak veriyi filtrelemek, sıralamak ve sınırlamak mümkündür.

Bu bölümde, önceki adımlarda oluşturduğumuz `company` veritabanındaki `member` tablosunu kullanarak temel `SELECT` sorgularını inceleyeceğiz.

Örnek `member` tablosu içeriği:

```
+----+------------+-----------+----------------------+------------+---------------------+---------------------+
| id | first_name | last_name | email                | birthday   | created_at          | updated_at          |
+----+------------+-----------+----------------------+------------+---------------------+---------------------+
|  1 | Yaşar      | Celep     | celep@veriteknik.com | 1996-12-23 | 2025-03-28 06:18:00 | 2025-03-28 06:18:00 |
|  2 | Ahmet      | Yılmaz    | ahmet@example.com    | 1990-05-15 | 2025-03-28 06:18:30 | 2025-03-28 06:18:30 |
|  3 | Ayşe       | Kaya      | ayse.kaya@example.net| NULL       | 2025-03-28 06:18:30 | 2025-03-28 06:18:30 |
|  4 | Mehmet     | Demir     | mehmet@example.org   | 1985-01-30 | 2025-03-28 06:18:30 | 2025-03-28 06:18:30 |
+----+------------+-----------+----------------------+------------+---------------------+---------------------+
```

## Tüm Sütunları Seçme (`SELECT *`)

Bir tablodaki tüm sütunları ve tüm satırları getirmek için `SELECT * FROM <tablo_adı>;` kullanılır:

```sql
SELECT * FROM member; 
```

Bu komut yukarıdaki örnek tablonun tamamını döndürür.

## Belirli Sütunları Seçme

Sadece istediğiniz sütunları getirmek için, sütun adlarını virgülle ayırarak belirtin:

```sql
SELECT first_name, last_name, email FROM member;
```

Örnek Çıktı:

```
+------------+-----------+----------------------+
| first_name | last_name | email                |
+------------+-----------+----------------------+
| Yaşar      | Celep     | celep@veriteknik.com |
| Ahmet      | Yılmaz    | ahmet@example.com    |
| Ayşe       | Kaya      | ayse.kaya@example.net|
| Mehmet     | Demir     | mehmet@example.org   |
+------------+-----------+----------------------+
```

## Satırları Filtreleme (`WHERE`)

Belirli koşullara uyan satırları seçmek için `WHERE` yan tümcesi kullanılır. Çeşitli karşılaştırma ve mantıksal operatörler kullanılabilir:

* **Eşitlik (`=`):**

  ```sql
  SELECT * FROM member WHERE first_name = 'Ahmet';
  ```
* **Eşit Değil (`!=` veya `<>`):**

  ```sql
  SELECT email FROM member WHERE first_name != 'Ayşe';
  ```
* **Karşılaştırma (`>`, `<`, `>=`, `<=`):**

  ```sql
  SELECT first_name, last_name FROM member WHERE birthday < '1995-01-01';
  ```
* **Desen Eşleştirme (`LIKE`):** Metin içinde kalıp aramak için kullanılır.

  * `%`: Sıfır veya daha fazla karakterle eşleşir.
  * `_`: Tek bir karakterle eşleşir.

  ```sql
  -- E-postası '.com' ile bitenler
  SELECT * FROM member WHERE email LIKE '%.com'; 
  -- Adı 'A' ile başlayanlar
  SELECT * FROM member WHERE first_name LIKE 'A%'; 
  -- Soyadının ikinci harfi 'e' olanlar
  SELECT * FROM member WHERE last_name LIKE '_e%'; 
  ```
* **Liste İçinde (`IN`):** Belirtilen değerlerden herhangi birine sahip olanları seçer.

  ```sql
  SELECT * FROM member WHERE id IN (1, 3);
  ```
* **Aralık (`BETWEEN ... AND ...`):** Belirtilen aralıktaki değerlere sahip olanları seçer (sınırlar dahil).

  ```sql
  SELECT * FROM member WHERE birthday BETWEEN '1990-01-01' AND '1999-12-31';
  ```
* **Boş Değer Kontrolü (`IS NULL`, `IS NOT NULL`):**

  ```sql
  -- Doğum tarihi girilmemiş olanlar
  SELECT * FROM member WHERE birthday IS NULL; 
  -- E-postası girilmiş olanlar
  SELECT * FROM member WHERE email IS NOT NULL; 
  ```
* **Koşulları Birleştirme (`AND`, `OR`):**

  ```sql
  -- Adı 'Ahmet' VE soyadı 'Yılmaz' olanlar
  SELECT * FROM member WHERE first_name = 'Ahmet' AND last_name = 'Yılmaz'; 
  -- ID'si 1 VEYA 4 olanlar
  SELECT * FROM member WHERE id = 1 OR id = 4; 
  -- 1990'dan önce doğmuş VE e-postası '.org' ile bitenler
  SELECT * FROM member WHERE birthday < '1990-01-01' AND email LIKE '%.org'; 
  ```

## Sonuçları Sıralama (`ORDER BY`)

Sonuçları belirli bir veya daha fazla sütuna göre sıralamak için `ORDER BY` kullanılır.

* **Artan Sıralama (`ASC` - Varsayılan):**

  ```sql
  SELECT * FROM member ORDER BY last_name ASC;
  -- veya sadece:
  SELECT * FROM member ORDER BY last_name;
  ```
* **Azalan Sıralama (`DESC`):**

  ```sql
  SELECT * FROM member ORDER BY birthday DESC;
  ```
* **Birden Fazla Sütuna Göre Sıralama:**

  ```sql
  -- Önce soyadına göre artan, aynı soyadına sahip olanları ada göre artan sırala
  SELECT * FROM member ORDER BY last_name ASC, first_name ASC; 
  ```

## Sonuç Sayısını Sınırlama (`LIMIT`)

Döndürülecek satır sayısını sınırlamak için `LIMIT` kullanılır. Genellikle `ORDER BY` ile birlikte kullanılarak en yüksek/düşük veya en yeni/eski kayıtları almak için kullanılır.

* **İlk N Kaydı Alma:**

  ```sql
  -- Eklenen ilk 2 üyeyi getir (ID'ye göre sıralı varsayarsak)
  SELECT * FROM member ORDER BY id ASC LIMIT 2; 
  ```
* **Belirli Bir Aralıktaki Kayıtları Alma (`LIMIT offset, count`):**\
  Sayfalama gibi işlemler için kullanılır. `offset` atlanacak satır sayısını, `count` ise getirilecek satır sayısını belirtir (ilk satırın offset'i 0'dır).

  ```sql
  -- 3. ve 4. üyeleri getir (2 satır atla, 2 satır getir)
  SELECT * FROM member ORDER BY id ASC LIMIT 2, 2; 
  ```

Bu temel `SELECT` komutları ve yan tümceleri, veritabanlarından bilgi almanın temelini oluşturur. Daha karmaşık sorgular için `JOIN`, gruplama (`GROUP BY`), fonksiyonlar gibi ileri konular bulunmaktadır.


# mysqldump ile yedekleme

`mysqldump`, MySQL ve MariaDB veritabanlarının mantıksal yedeklerini (logical backup) almak için kullanılan standart bir komut satırı aracıdır. Oluşturduğu yedek dosyası, veritabanını ve/veya tabloları yeniden oluşturmak için gerekli SQL ifadelerini (`CREATE DATABASE`, `CREATE TABLE`, `INSERT INTO` vb.) içeren bir metin dosyasıdır.

Bu yöntem, fiziksel yedeklemeye (veritabanı dosyalarını doğrudan kopyalama) göre genellikle daha esnektir (farklı sürümler veya mimariler arasında taşınabilir), ancak büyük veritabanları için yedekleme ve geri yükleme işlemi daha uzun sürebilir.

## Temel Kullanım

`mysqldump` komutu genellikle şu formatta kullanılır:`mysqldump [seçenekler] <veritabanı_adı> [tablo_adları...] > yedek_dosyasi.sql`

* **Tek Bir Veritabanını Yedekleme:**

  ```bash
  mysqldump -u <kullanıcı> -p <veritabanı_adı> > yedek.sql
  ```

  Komut, belirtilen kullanıcının şifresini soracaktır. `<veritabanı_adı>` yerine yedeklenecek veritabanının adını yazın. Çıktı (`yedek.sql` dosyası) tüm `CREATE TABLE` ve `INSERT INTO` ifadelerini içerecektir.
* **Birden Fazla Veritabanını Yedekleme:**`--databases` seçeneği ile birden fazla veritabanı belirtilebilir. Bu seçenek kullanıldığında, yedek dosyası `CREATE DATABASE IF NOT EXISTS` ve `USE <veritabanı_adı>` ifadelerini de içerir.

  ```bash
  mysqldump -u <kullanıcı> -p --databases <db1_adı> <db2_adı> > coklu_yedek.sql
  ```
* **Tüm Veritabanlarını Yedekleme:**\
  Sunucudaki tüm veritabanlarını yedeklemek için `--all-databases` seçeneği kullanılır.

  ```bash
  mysqldump -u root -p --all-databases > tum_yedekler.sql
  ```

  Bu komut genellikle `root` veya tüm veritabanlarına erişim yetkisi olan bir kullanıcı ile çalıştırılır.
* **Sadece Belirli Tabloları Yedekleme:**\
  Veritabanı adından sonra boşlukla ayırarak sadece belirli tablo adları yazılabilir:

  ```bash
  mysqldump -u <kullanıcı> -p <veritabanı_adı> tablo1 tablo3 > tablolar_yedek.sql
  ```

## Yaygın Kullanılan Seçenekler

* **`-u <kullanıcı>`, `-p`**: Veritabanına bağlanmak için kullanıcı adı ve şifre istemi. Şifreyi doğrudan komut satırında `-p<şifre>` şeklinde (boşluksuz) yazmak mümkündür ancak güvenlik açısından önerilmez (komut geçmişinde görünebilir).
* **`--host=<host_adı>`, `--port=<port_no>`**: Eğer veritabanı sunucusu yerel makinede değilse veya standart portu (3306) kullanmıyorsa bağlantı bilgilerini belirtir.
* **`--result-file=<dosya_adı>`**: Çıktıyı `>` yönlendirmesi yerine doğrudan belirtilen dosyaya yazar.
* **`--single-transaction`**: **(InnoDB tabloları için önerilir)** Yedekleme işlemi başlamadan önce bir veritabanı anlık görüntüsü (snapshot) oluşturur ve tüm yedeklemeyi bu anlık görüntü üzerinden tek bir işlem (transaction) içinde yapar. Bu, yedekleme sırasında tabloların kilitlenmesini engeller ve tutarlı bir yedek alınmasını sağlar. MyISAM gibi transactional olmayan tablolar için etkisi yoktur. `--lock-tables` ile birlikte kullanılmamalıdır.
* **`--quick` (-q)**: Büyük tablolar için önerilir. `mysqldump`'ın tüm tablo içeriğini belleğe almasını engeller, bunun yerine satır satır okuyup yazar.
* **`--routines` (-R)**: Saklı yordamları (stored procedures) ve fonksiyonları (functions) yedek dosyasına dahil eder.
* **`--triggers`**: Tablolara ait tetikleyicileri (triggers) yedek dosyasına dahil eder. (Genellikle varsayılan olarak dahildir).
* **`--events` (-E)**: Zamanlanmış olayları (scheduled events) yedek dosyasına dahil eder.
* **`--no-data` (-d)**: Sadece veritabanı ve tablo yapılarını (schema) yedekler, verileri (`INSERT` ifadelerini) dahil etmez. Boş bir veritabanı yapısı oluşturmak için kullanışlıdır.
* **`--databases`**: Yedeklenen veritabanları için `CREATE DATABASE` ifadelerini ekler. Birden fazla veritabanı yedeklerken kullanışlıdır.
* **`--all-databases`**: Tüm veritabanları için `CREATE DATABASE` ifadelerini ekler.
* **`--add-drop-database`**: `--all-databases` veya `--databases` ile kullanıldığında, `CREATE DATABASE` ifadesinden önce `DROP DATABASE IF EXISTS` ifadesini ekler. Geri yüklerken mevcut veritabanının silinmesini sağlar (dikkatli kullanılmalıdır!).
* **`--add-drop-table`**: Her `CREATE TABLE` ifadesinden önce `DROP TABLE IF EXISTS` ifadesini ekler. Geri yüklerken mevcut tabloların silinmesini sağlar.

## Yedekleri Sıkıştırma

`mysqldump` çıktısı genellikle büyük olabilen bir metin dosyasıdır. Disk alanı kazanmak için çıktıyı doğrudan `gzip`, `zstd` gibi bir sıkıştırma aracına pipe ile göndermek yaygın bir pratiktir:

```bash
# gzip ile sıkıştırma
mysqldump -u root -p --single-transaction --all-databases | gzip > tum_yedekler.sql.gz

# zstd ile sıkıştırma (daha modern ve hızlı)
mysqldump -u root -p --single-transaction --all-databases | zstd > tum_yedekler.sql.zst
```

## Yedekleri Geri Yükleme

`mysqldump` ile alınan `.sql` (veya sıkıştırılmış) dosyaları geri yüklemek için `mysql` (veya `mariadb`) komut satırı istemcisi kullanılır. Bu işlem [Yedekleri İçeri Alma](/veritabani/mysql/yedekleri-iceri-alma) bölümünde anlatılmaktadır.

`mysqldump`, MySQL/MariaDB veritabanlarını yedeklemek için esnek ve güçlü bir araçtır. Özellikle `--single-transaction` gibi seçenekler, canlı sistemlerde tutarlı yedekler almak için önemlidir.


# Replikasyon teknikleri

Veritabanı replikasyonu, verilerin bir veritabanı sunucusundan (genellikle **kaynak (source)**, **birincil (primary)** veya eski adıyla **master** olarak adlandırılır) bir veya daha fazla başka veritabanı sunucusuna (**kopya (replica)** veya eski adıyla **slave**) kopyalanması işlemidir.

## Replikasyonun Amaçları

* **Yüksek Erişilebilirlik (High Availability):** Kaynak sunucuda bir sorun olması durumunda, kopyalardan birinin onun yerini alarak (failover) hizmet kesintisini en aza indirmek.
* **Okuma Ölçeklendirme (Read Scaling):** Yoğun okuma işlemleri olan uygulamalarda, okuma sorgularını kopyalara yönlendirerek kaynak sunucunun yükünü azaltmak. Yazma işlemleri hala kaynağa yapılır.
* **Yedekleme:** Canlı kaynak sunucuyu etkilemeden, kopyalardan birinden güvenli bir şekilde yedek almak.
* **Analiz/Raporlama:** Uzun süren analiz veya raporlama sorgularını kaynak sunucuyu yavaşlatmadan kopyalar üzerinde çalıştırmak.
* **Coğrafi Dağıtım:** Veriyi farklı coğrafi konumlardaki kullanıcılara daha yakın tutmak.

## Standart Asenkron Replikasyon

MySQL ve MariaDB'de en yaygın kullanılan replikasyon türü **asenkron (asynchronous)** kaynak-kopya (source-replica / master-slave) replikasyonudur.

**Nasıl Çalışır?**

1. **Binary Log (Binlog):** Kaynak sunucu, veritabanında yapılan tüm değişiklikleri (INSERT, UPDATE, DELETE vb. ifadeler veya satır değişiklikleri) **binary log** adı verilen özel bir log dosyasına yazar. Bu log, replikasyonun temelini oluşturur.
2. **I/O Thread (Kopya):** Kopya sunucu, kaynak sunucuya bağlanır ve kaynak sunucunun binary log'undaki yeni olayları okumak için bir **I/O thread** başlatır.
3. **Relay Log (Kopya):** Kopya sunucunun I/O thread'i, kaynaktan okuduğu olayları kendi yerel disindeki **relay log** dosyalarına yazar.
4. **SQL Thread (Kopya):** Kopya sunucu, relay log'ları okuyup içindeki SQL olaylarını kendi veritabanı üzerinde yürütmek için bir **SQL thread** (veya modern sürümlerde birden fazla paralel thread) başlatır.

Bu süreç asenkrondur, yani kaynak sunucu bir işlemi tamamladıktan sonra kopyanın o işlemi uygulamasını beklemez. Bu nedenle, kopya sunucu genellikle kaynak sunucunun biraz gerisinde olabilir (**replica lag**).

**Binlog Formatları:**

* **Statement-Based Replication (SBR):** Kaynak sunucu, çalıştırılan SQL ifadelerini (`INSERT`, `UPDATE` vb.) binlog'a yazar. Kopya bu ifadeleri tekrar çalıştırır. Basittir ancak bazı durumlarda (örn. `UUID()`, `NOW()` gibi deterministik olmayan fonksiyonlar, `LIMIT` içeren `UPDATE`/`DELETE`) tutarsızlıklara yol açabilir.
* **Row-Based Replication (RBR):** Kaynak sunucu, SQL ifadelerini değil, değişen *satırların* önceki ve sonraki hallerini binlog'a yazar. Kopya bu satır değişikliklerini doğrudan uygular. Genellikle daha güvenilir ve tutarlıdır, çoğu modern sistem için **önerilen** formattır. Ancak binlog boyutu daha büyük olabilir.
* **Mixed-Based Replication (MBR):** Varsayılan olarak SBR kullanır, ancak SBR için güvenli olmayan ifadelerle karşılaştığında otomatik olarak RBR'ye geçer.

Binlog formatı, kaynak sunucunun yapılandırmasında (`binlog_format` değişkeni) ayarlanır.

**Replikasyon Konumlandırma:**

Kopyanın, kaynağın binlog'unda hangi noktadan itibaren okumaya başlayacağını bilmesi gerekir. İki ana yöntem vardır:

* **Klasik (Binlog Dosyası + Pozisyon):** Kopya, belirli bir binlog dosyasının (`mysql-bin.000123`) belirli bir bayt pozisyonundan (`154`) okumaya başlar. Kaynak sunucuda `SHOW MASTER STATUS;` komutu ile mevcut dosya ve pozisyon görülebilir.
* **GTID (Global Transaction Identifiers):** Modern MySQL (5.6+) ve MariaDB (10.0+) sürümlerinde **önerilen** yöntemdir. Her bir işlem (transaction) küresel olarak benzersiz bir kimlik (GTID) alır. Kopya, hangi GTID'leri zaten uyguladığını takip eder ve kaynaktan sadece eksik olanları ister. Bu, failover ve topoloji değişikliklerini çok daha kolay hale getirir. Yapılandırmada `gtid_mode=ON` ve `enforce_gtid_consistency=ON` ayarları gereklidir.

## Temel Asenkron Replikasyon Kurulum Adımları (Kavramsal)

Aşağıdaki adımlar genel bir fikir vermek içindir, detaylar sürüme ve yapılandırmaya göre değişebilir. GTID kullanıldığı varsayılmıştır.

1. **Kaynak Sunucu Yapılandırması (`my.cnf` veya `my.ini`):**
   * Benzersiz bir `server-id` ayarlayın (örn. `server-id = 1`).
   * Binary log'u etkinleştirin (`log-bin = mysql-bin`).
   * (Önerilen) GTID'yi etkinleştirin (`gtid_mode = ON`, `enforce_gtid_consistency = ON`).
   * (Önerilen) RBR kullanın (`binlog_format = ROW`).
   * Servisi yeniden başlatın.
2. **Replikasyon Kullanıcısı Oluşturma (Kaynakta):**\
   Kopyanın kaynağa bağlanmak için kullanacağı bir kullanıcı oluşturun ve gerekli replikasyon yetkilerini verin:

   ```sql
   CREATE USER 'replica_user'@'<kopya_sunucu_ip>' IDENTIFIED BY 'guclu_bir_sifre';
   GRANT REPLICATION SLAVE ON *.* TO 'replica_user'@'<kopya_sunucu_ip>';
   FLUSH PRIVILEGES;
   ```
3. **Kaynak Veritabanının Anlık Görüntüsünü Alma:**\
   Tutarlı bir başlangıç noktası için kaynağın yedeğini alın. `mysqldump` kullanılıyorsa, GTID bilgilerini de içeren bir yedek almak önemlidir:

   ```bash
   mysqldump -u root -p --all-databases --single-transaction --routines --triggers --events --master-data=2 --gtid > kaynak_yedek.sql 
   # veya mariadb-dump kullanın
   ```

   `--master-data=2` (veya `--dump-slave=2`) ve `--gtid` seçenekleri, yedek dosyasına o anki GTID bilgisini (`SET @@GLOBAL.GTID_PURGED=...`) ekler.
4. **Kopya Sunucu Yapılandırması (`my.cnf` veya `my.ini`):**
   * Kaynaktan farklı, benzersiz bir `server-id` ayarlayın (örn. `server-id = 2`).
   * (Önerilen) GTID'yi etkinleştirin (`gtid_mode = ON`, `enforce_gtid_consistency = ON`).
   * (Önerilen) Kopyanın sadece okunur olmasını sağlayın (`read_only = 1` veya `super_read_only = 1`).
   * Relay log ayarlarını yapın (örn. `relay-log = kopya-relay-bin`).
   * (Önerilen) Kopyanın kendi değişikliklerini de binlog'a yazmasını sağlayın (`log-bin = kopya-bin`, `log_slave_updates = 1`) - bu, zincirleme replikasyon veya kolay failover için gereklidir.
   * Servisi yeniden başlatın.
5. **Yedeği Kopyaya Geri Yükleme:**\
   Kaynak sunucudan alınan yedek dosyasını kopya sunucuya aktarın ve `mysql` istemcisi ile geri yükleyin:

   ```bash
   mysql -u root -p < kaynak_yedek.sql
   ```
6. **Kopyayı Kaynağa Bağlama (`CHANGE MASTER TO` / `CHANGE REPLICATION SOURCE TO`):**\
   Kopya sunucuda, kaynağa nasıl bağlanacağını ve hangi noktadan başlayacağını belirtin (GTID kullanılıyorsa dosya/pozisyon yerine `MASTER_AUTO_POSITION=1` veya `SOURCE_AUTO_POSITION=1` kullanılır):

   ```sql
   -- MySQL 8.0.23+ / MariaDB 10.5.1+
   CHANGE REPLICATION SOURCE TO
     SOURCE_HOST='<kaynak_sunucu_ip>',
     SOURCE_USER='replica_user',
     SOURCE_PASSWORD='guclu_bir_sifre',
     SOURCE_AUTO_POSITION=1; -- GTID kullan

   -- Eski Sürümler
   -- CHANGE MASTER TO 
   --   MASTER_HOST='<kaynak_sunucu_ip>',
   --   MASTER_USER='replica_user',
   --   MASTER_PASSWORD='guclu_bir_sifre',
   --   MASTER_AUTO_POSITION=1; -- GTID kullan
   ```
7. **Replikasyonu Başlatma:**\
   Kopya sunucuda replikasyon thread'lerini başlatın:

   ```sql
   -- MySQL 8.0.22+ / MariaDB 10.5.1+
   START REPLICA;

   -- Eski Sürümler
   -- START SLAVE;
   ```
8. **Replikasyon Durumunu Kontrol Etme:**\
   Kopya sunucuda replikasyonun durumunu kontrol edin. `Slave_IO_Running` (veya `Replica_IO_Running`) ve `Slave_SQL_Running` (veya `Replica_SQL_Running`) durumlarının `Yes` olması ve `Seconds_Behind_Master` (veya `Seconds_Behind_Source`) değerinin düşük olması beklenir.

   ```sql
   -- MySQL 8.0.22+ / MariaDB 10.5.1+
   SHOW REPLICA STATUS\G

   -- Eski Sürümler
   -- SHOW SLAVE STATUS\G 
   ```

   (`\G` çıktıyı dikey formatta gösterir).

## Diğer Replikasyon Türleri

* **Yarı Senkron (Semi-Synchronous) Replikasyon:** Kaynak, işlemi tamamlamadan önce en az bir kopyanın olayı kendi relay log'una yazdığını teyit eder. Asenkrona göre veri kaybı riskini azaltır ancak performansı biraz düşürebilir.
* **Grup Replikasyonu (Group Replication - MySQL):** Birden fazla sunucunun aktif olarak birbirini güncellediği, çakışma tespiti ve otomatik failover sağlayan daha gelişmiş bir topolojidir.
* **Galera Cluster (MariaDB/Percona):** Neredeyse senkron, çoklu kaynak (multi-primary) replikasyon sağlayan, otomatik node ekleme/çıkarma ve failover özelliklerine sahip bir kümeleme çözümüdür.

Replikasyon, veritabanı sistemlerinin ölçeklenebilirliğini ve dayanıklılığını artırmak için güçlü bir araçtır, ancak dikkatli planlama ve yapılandırma gerektirir.




---

[Next Page](/llms-full.txt/1)

