Unix/Linux Shell ve Shell Script

15 Eki

Kullanıcıların bir bilgisayar organizasyonuna iş yaptırabilmesi için onunla iletişime geçebilmesi gerekir. İşletim sistemi çekirdek yazılımları, son kullanıcıların erişip işlem yapabileceği ortamlar değildir. Bu nedenle kullanıcıların programlar ve komutlar aracılığı ile işletim sistemine ulaşabilmesi ve bilgisayara iş yaptırabilmesi için ara yazılımlar geliştirilmektedir. Bu ara yazılımlar komut satırı veya grafik arabirimi şeklinde olabilmektedir.

Unix veya Linux shell, Linux işletim sistemine erişmek için kullanılan bir kullanıcı arayüzüdür. Kullanıcıların dosya sisteminde gezinmek, dosyaları yönetmek, programları çalıştırmak ve sistemi yapılandırmak gibi görevleri gerçekleştirmek için komutlar yazmasına imkan tanıyan bir programdır.

Linux Ubuntu Shell

Command Prompt olarak adlandırılan $ promptu shell tarafından kullanıcıya sunulur. Shell girilen komutları buradan okur.

Shell Türleri

İki temel shell türü bulunmaktadır.

  • Bourne shell − Eğer Bourne shell kullanılıyorsa, $ karakteri default prompt olarak gelir.
  • C shell − Eğer C shell kullanılıyorsa, % karakteri default prompt olarak gelir.

Bourne shell alt türleri

  • Bourne shell (sh), bulunduğu dizin /bin/sh
  • Korn shell (ksh), bulunduğu dizin /bin/ksh or /bin/ksh93
  • Bourne Again shell (bash), bulunduğu dizin /bin/bash
  • POSIX shell (sh), bulunduğu dizin /bin/ps

C shell alt türleri

  • C shell (csh), bulunduğu dizin /bin/csh
  • TENEX/TOPS C shell (tcsh), bulunduğu dizin /bin/tcsh

Shell Sctipt

Bir shell script temel olarak, yürütme sırasına göre sıralanan komutlar bir listesidir. İyi bir shell scriptte, # işaretinin önünde adımları açıklayan açıklamalar bulunur.

Script içerisinde programlama mantıığında kullanılan koşullu ifadeler, döngüler, dosya işlemleri, değişken tanımlama ve okuma gibi işlemlerin yanısıra fonksiyonlar da tanımlanabilir.

Örnek shell script

Script dosyaları .sh uzantılı olmalıdır. Script’e bir şey eklemeden önce, sistemi bir shell script başlatıldığı konusunda uyarmak gerekir. Bu uyarı aşağıdaki gibi yapılır.

#!/bin/sh

Bu ifade, sisteme aşağıdaki komutların Bourne shell tarafından yürütüleceğini bildirir. Buna shebang denir çünkü # sembolüne hash denir ve ! sembole bang denir.

#!/bin/bash

# Author : Bayram Üçüncü
# Copyright (c) bayramucuncu.com
# Script follows here:
pwd
ls

Bu dosyayı test.sh olarak kaydederek çalıştırılabilir hale getirmek gereklidir.

$ chmod +x test.sh

Çalıştırılabilr test.sh dosyası aşağıdaki şekilde çalıştırılır.

$ ./test.sh

Programın çalıştırılması için ./program_adı kullanılır.

dotnet nuget kullanımı

15 Eki

NuGet, .NET’in paket yöneticisidir. NuGet geliştirici araçları, paket oluşturma ve kullanma desteği sağlar. NuGet Galerisi, tüm paket yazarları ve tüketicileri tarafından kullanılan merkezi bir paket deposudur. Oluşturulanpaketler, güvenli yöntemler ile geleriye gönderilir ve alınır.

Nuget paketi oluşturmadan önce örnek bir dotnet projesi oluşturmak için aşağıdaki komut kullanılabilir.

dotnet new classlib -n DotnetNugetSample

Proje içerisinde de basit bir ILogger interface olabilir.

Bu proje öncelikle bir nuget paketi haline getirilmelidir.

dotnet pack .\DotnetNugetSample\ -o packages
Dotnet package

Oluşturulan bu paketi başka projelerde kullanmak için iki farklı yöntem izlenebilir.

1. local ortamda başka bir projede ilgili packages klasörü bir nuget source olarak eklenir.

dotnet nuget add source D:\nugetsample\packages -n MyNugetPackages

2. sunucuda bir nuget repository üzerine eklenir.

dotnet nuget push D:\nugetsample\packages\DotnetNugetSample.1.0.0.nupkg -s https//api.nuget.org/v3/index.json -k secretkey

Bu işlem ile nuget paketi artık her yerden erişilebilir hale gelir.

Paketi sunucudan silmek için aşağıdaki komut kullanılabilir.

dotnet nuget delete DotnetNugetSample 1.0.0 -s https//api.nuget.org/v3/index.json -k secretkey

Unit Test ve Kodun Varlığının Testi

15 Eki

Aşağıda bulunan controller sınıfının test edileceğini düşünelim.

[ApiController]
[Route("api/[controller]")]
public class TodoItemsController : ApiControllerBase
{
    [HttpGet]
    public async Task<ActionResult<TodoItemBriefDto>> GetTodoItems([FromQuery] Query query)
    {
        return await Mediator.Send(query);
    }
}

Soru: Sınıfa ait her şeyi test etmeli miyim?

1 – TodoItemsController sınıfı ApiControllerAttribute attribute sahiptir.
2 – TodoItemsController sınıfı RouteAttribute attribute sahiptir.
3 – TodoItemsController sınıfı “GetTodoItems” isimli bir meoda sahiptir.
4 – RouteAttribute attribute “api/[controller]” diye bir parametreye sahiptir.
5 – GetTodoItems metodu ActionResult döndürür.
6 – GetTodoItems metodu Query tipinde bir parametre alır.
7 – GetTodoItems metodu TodoItemBriefDto tipinde bir sonuç verir.
8 – GetTodoItems metodu null bir Query parametresine ArgumentNullException fırlatır.
9 – GetTodoItems metodu Query parametresi ile TodoItemBriefDto tipinde bir sonuç döndürür.

Unit test olarak bu testlerin hangileri yazılmalıdır?

Eğer unit test yazıyorsak, bir unit (metod) için belli girdiler ile belli sonuçların döndürdüğünü incelememiz gerekir. Çünkü unit testte kodun varlığı ve işlevselliği test edilir.

O halde yukarıdaki maddelerde 8 ve 9 numaralı maddelerde bir unit(method) test yapılmaktadır.
Diğer maddeler ise kodun var olup olmadığını test etmek için yazılmıştır.

Unit Test metodlarında bulunması gereken özelliklerden burada bahsedilmiştir.

C# Thread ve Task Kullanımı

15 Eki

İşletim sistemleri, verilen görevleri iş parçacıkları ile süreçler halinde yerine getirirler. İşletim sistemindeki bir süreç, temel olarak yürütülmekte olan bir programdır. Program içerisinde yürütülmesi istenen işler bir veya birden fazla thread (iş parçacığı) ile yürütülebilmektedir. Bilgisayar programlamada dilin sağladığı özellikler sayesinde iş parçacıkları asenkron olarak yönetilebilmektedir. Her program bir ana thread ile ayağa kalkıp işi bitene kadar bu thread ile yürütülmektedir. Programı asenkron yönetmek, programın alt süreçlerini, ana thread dışında bir veya birden fazla thread ile yürütmektir.

Özellikle çok çekirdekli işlemcilerden tam performans alabilmek için birden fazla thread ile asenkron işlemler gerçekleştirilebilmektedir. Buna multithreading denilmektedir.

C# Thread ve Task sınıfları

C# programlama dilinde asenkron işlemler için Thread ve Task olmak üzere iki sınıf tanımlanmıştır. (Linkler .Net 7.0 versiyonu doküman sayfasına aittir.)

Thread Sınıfı

Thread sınıfı bir iş parçacığı oluşturup denetler, çalışma önceliğini ayarlar ve durumunu bildirir. Geriye bir değer döndürmeyen, asenkron çalışan tek bir işlemi temsil eder. C# ortamında çalışan bir thread hakkında bazı temel bilgileri elde etmek mümkündür.

// Thread Id bilgisi
Thread.CurrentThread.ManagedThreadId

// Thread durum bilgisi
Thread.CurrentThread.ThreadState
 
// Background olup olmadığı bilgisi
Thread.CurrentThread.IsBackground

//ThreadPool'dan alınıp alınmadığı bilgisi
Thread.CurrentThread.IsThreadPoolThread

Thread nesnesi oluşuturma örneği;

// Run with new Thread
var thread = new Thread(()=>Write("*"));
thread.Start();

// Run with Main Thread 
Write("-");

void Write(string input)
{
    for (var i = 0; i < 10; i++)
        Console.Write(input);
}

// Output
--**----********----

Aynı Write metodu hem main thread hemde thread nesnesi tarafından çalıştırılmaktadır. Output incelendiğinde biraz “*” karakteri biraz “-” karakterinin ekrana yazıldığı görülmektedir.

C# dilinde yönetilen (managed) thread,ya arka planda (background) ya da ön planda (foreground) çalışır. Thread’in bu özelliğini öğrenmek için Thread.IsBackground property kullanılır.

Foreground Thread

Foreground thread, main thread’in işini bitirip sonlanmasından etkilenmez. Kendi işi bittiğinde sonlanır. Bu, C#’ta ön plandaki bir iş parçacığının ömrünün ana iş parçacığına bağlı olmadığı anlamına gelir. Thread’ler default olarak foreground özelliğinde oluşturulurlar.

var thread = new Thread(()=>Write("*"));
thread.Start();

Console.WriteLine("Main thread finished");

void Write(string input)
{
    for (var i = 0; i < 10; i++)
    {
        Thread.Sleep(100);
        Console.Write(input);
    }
}


// Output
Main thread finished
**********

thread.Start() metodu çalıştırıldıktan sonra main thread Console.WriteLine(“Main thread finished”); metodunu çağırır ve main program sonlanır. Ancak thread nesnesi, foreground özelliğinde olduğu için işini bitirene kadar çalışmaya devam eder.

Background Thread

Background thread’lerin çalışması main thread veya diğer tüm foreground thread’lerin çalışır olması durumda olmasına bağlıdır.

var thread1 = new Thread(()=>Write("*"));
thread1.IsBackground = true;
thread1.Start();

Console.WriteLine("Main thread finished");

void Write(string input)
{
    for (var i = 0; i < 10; i++)
    {
        Thread.Sleep(100);
        Console.Write(input);
    }
}


// Output
Main thread finished

Burada main thread Console.WriteLine(“Main thread finished”); metodunu çağırıp hemen sonlandığı için background thread de işini yapamadan yani ekrana birşey yazamadan sonlanmıştır. Eğer bir foreground thread2 tanımlanıp çalıştırılsaydı, o bitene kadar thread1 işini yapacaktı.

Task Sınıfı

Task sınıfı asenkron bir operasyonu temsil eder. Task-based asyncronious pattern kavramının tamel yapı taşıdır. İşlem sonucunda geriye bir değer döndürebilme özelliğine sahiptir.

Lambda ifadesi ile task nesnesi oluşturma;

Task t1 = new Task(
    () => Console.WriteLine("Working"));
t1.Start();
// t1'nin çalıştığını göstermek için main thread bloke edilsin.
t1.Wait();

Parametre alan Lambda ifadesi ile task nesnesi oluşturma;

Task t1 = new Task(
    param=> Console.WriteLine($"Working param: {param}"), 2);
t1.Start();
// t1'nin çalıştığını göstermek için main thread bloke edilsin.
t1.Wait();

Action metod task nesnesi oluşturma;

var action = (object? param) =>{
    Console.WriteLine($"I am working with param: {param}");
};

Task t1 = new Task(action, 2);
t1.Start();
// t1'nin çalıştığını göstermek için main thread bloke edilsin.
t1.Wait();

Task nesneleri arka plan (background) thread olarak hizmet vermektedir. Bu nedenle main thread sonlanmadan çalışmasını görebilmek için t1.Wait(); kullanılmıştır.

var action = (object? param) =>{
    Console.WriteLine(Thread.CurrentThread.IsBackground);
    Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread);
    Console.WriteLine($"I am working with param: {param}");
};

Task t1 = new Task(action, 2);
t1.Start();
t1.Wait();

Task nesnelerinin kullandıkları thread, ThreadPool’a aittir. Bunu Thread.CurrentThread.IsThreadPoolThread property ile anlayabiliriz.

ThreadPool Nedir? ThreadPool Neden Kullanılır?

ThreadPool tipi, uygulamada görevleri yürütmek, asenkron I/O süreçlerini işletmek, timer’ları işletmek gibi işlemler için bir thread havuzu sunar. Task objeleri, bu havuz içerisinden bir thread alarak işlemlerini yürütürler. Bu sayede thread oluşturma, oluşturulan thread için resource ayırma, görevi yürütme ve Garbage Colleciton ile kaynakların serbest bırakılması adımları tekrar tekrar işletilmez. ThreadPool’da arka planda bir dizi görevi gerçekleştirmek için yeniden kullanılabilecek bir thread havuzundan yeniden kullanılabilir thread’lerden bir tane alınarak işlemeler gerçekleştirilir ve thread havuza geri bırakılır.

ThreadPool üzerindeki aktif thread sayısını şu şekilde öğrenmek mümkündür;

Console.WriteLine(ThreadPool.ThreadCount);

ThreadPool üzerinde tanımlanabilecek maksimum worker thread sayısı ve maksimum I/O işlemleri için kullanılabilecek thread sayısını şu şekilde öğrenilebilir;

ThreadPool.GetMaxThreads(out var worker, out var ioCompletion);
Console.WriteLine("{0} / {1}", worker, ioCompletion);

Task içerisinde çalışan thread, ThreadPool içerisinden alınır.

Task Oluşturma ve Yürütme

Bir taskı oluşturmak ve yürütmek için birden fazla yöntem vardır. En yaygın kullanılanı ise Task.Run() metodudur. Bu yöntemde Task default parametreleri ile oluşturulur ve kullanılır.

 Task.Run(() =>
 {
     Console.WriteLine("Working");
     Console.WriteLine(Thread.CurrentThread.IsBackground);
     Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread);
 });

Bir diğer yöntem ise Task.Factory.StartNew() statik metodunun çalıştırılmasıdır. Bu yöntemde StartNew() metodunun overload edilmiş tipleri ile Task’a parametre geçilebilmektedir.

 Task.Factory.StartNew(() =>
 {
     Console.WriteLine("Working");
     Console.WriteLine(Thread.CurrentThread.IsBackground);
     Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread);
 });

Merhaba Linux Ubuntu Desktop

9 Eki

İş dünyasındaki sunucu ortamlarda sürekli haşır neşir olduğum linux işletim sistemi, son yıllarda container ortamların iyice yaygınlaşmasıyla birlikte yol arkadaşım oldu.

Kişisel bilgisayarımda Linux işletim sistemine taşınmak, uzun süredir aklımda olan planlardan biriydi. Bunun en önemli nedeni, bilgisayrımda yaşadığım kaynak yetersizliğiydi. Bu yetersizliğin en önemli nedenlerinden biri de Windows işletim sistemi üzerinde Linux tabanlı araçlarının kurulabilmesi için yüklenen sanallaştırma platformlarıydı. Bir süre sonra windows üzerinde terminali bile linux tabanlı kullanmaya başlamıştım. O halde uzun süredir kullandığım Windows işletim sisteminden Linux ortamında bir desktop dağıtıma geçme vaktinin geldiğine karar verdim. Community desteğinin de geniş olması nedeniyle seçimim Ubuntu desktop oldu.

Linux dünyasına geçmeden önce geliştirme araçlarımın linux desteğini inceledim ve artık geçişi başlatmaya karar verdim. Refus programı ile bir USB kurlum olşuturdum ve yedekteki SSD diskim üzerine kurulumu yaptım.

Windows çok kullanışlı ve alışık olduğum bir işletim sistemi olması nedeniyle, Linux desktopa alışamam bir hafta kadar sürdü. Kurulumlar, dosya sistemi, sürücülerin tanıtılması vs. derken bir hafta sonunda acemiliğimi atmış oldum. Server versiyondan alışık olduğum için bir çok kurulumu terminal ile yapmaya çalıştım.

Performans konusunda gayet memnun kaldım. Windows üzerinde container ortamlarda ayağa kaldırdığım araçları Linux üzerinde kaldırdığımda kaynak kullanımı neredeyse %50 civarında fark ettiğini gördüm. Bilgisayarın rahatlamasıyla bende rahat bir nefes almış oldum.

Sonuç olarak, eğer geliştirme değil de ofis veya ev amaçlı bir desktop işletim sistemi seçecek olursam yine windows tercih ederdim. Ancak yazılım ve mühendislik amaçlı kullanımda Unix tabanlı bir işletim sistemini (Linux veya Mac) tercih ederim.