GUI (Grafiksel Kullanıcı Arayüzü)

os/exec (Komut Satırına Erişim)

os/exec paketi komut satırına (cmd, powershell, terminal) komut göndermemizi sağlayan Golang ile bütünleşik gelen bir pakettir. Bu paket sayesinde oluşturacağımız programa sistem işlerini yaptırabiliriz. Örnek olarak dosya/klasör taşıma/silme/oluşturma/kopyalama gibi işlemleri yaptırabilir. Daha doğrusu komut satırı/terminal üzerinden yapabildiğimiz her işlemi yaptırabiliriz. Tabi kullandığımız işletim sistemine göre terminal komutları değiştiği için ona göre örnek vermeye çalışacağım.

Örnek 1: Komut Satırına Komut Gönderme Ufak bir örnek ile başlayalım.

package main
import (
"os"
"os/exec"
)
func main() {
cmd := exec.Command("mkdir", "klasörüm")
cmd.Stdout = os.Stdout
cmd.Run()
}

“mkdir klasörüm” komutu programın çalıştırıldığı dizinde “klasörüm” adında bir klasör oluşturur. Komut girerken dikkat etmeniz geren çok önemi bir detay var. Yazacağınız komut birden fazla kelimeden oluşuyorsa mutlaka ayrı ayrı girmelisiniz. Eğer exec.Command() fonksiyonuna direkt olarak “mkdir klasörüm” olarak girseydik, komutu tek kelime olarak algılayacaktı. Yani string dizisi mantığında çalışıyor bu olay. Sonuç olarak yukarıdaki gibi basit bir şekilde komut satırına komut yollayabilirsiniz. Örnek 2: Komut Satırına Komut Gönderip Çıktısını Okuma Yukarıda çok kolay bir şekilde komut göndermeyi gördük. Fakat iş komutun çıktısını okumaya gelince işler biraz karışıyor. Yavaştan vaziyetinizi alın Wink Aslında korkulacak bir olay yok. Yeter ki mantığını anlayalım. Şimdi yapacağımız işlemleri 4 ana parçaya bölelim.

  1. Komutun tanımlanması

  2. Çıktı okuyucusunun tanımlanması

  3. Komutun başlatılması

  4. Komutun çalışması

Hemen kodlarımıza geçelim.

package main
import (
"bufio"
"fmt"
"os"
"os/exec"
)
func main() {
//komutun tanımlanması
cmd := exec.Command("go", "version")
cmdOkuyucu, hata := cmd.StdoutPipe()
if hata != nil {
fmt.Fprintln(os.Stderr, "Çıktı okunurken hata oluştu:", hata)
os.Exit(1)
}
//çıktı okuyucusunun tanımlanması
çıktı := bufio.NewScanner(cmdOkuyucu)
go func() {
for çıktı.Scan() {
fmt.Println(çıktı.Text())
}
}()
//komutun başlatılması
hata = cmd.Start()
if hata != nil {
fmt.Fprintln(os.Stderr, "Komut başlatılamadı:", hata)
os.Exit(1)
}
//komutun çalışması
hata = cmd.Wait()
if hata != nil {
fmt.Fprintln(os.Stderr, "Komut çalışırken hata oluştu:", hata)
os.Exit(1)
}
}

Gelelim yukarıdaki kodların açıklamasına… cmd adında bir değişken oluşturduk. Bu değişkenimiz sayesinde exec.Command() fonksiyonuyla komutlarımızı girdik. cmd.StdoutPipe() fonksiyonuyla gönderdiğimiz komutun çıktılarını alabiliyoruz. cmdOkuyucu değişkenine komut çıktımızı aldık. hata değişkenimize ise komut girildiğinde oluşan hata mesajını aldık. hata değişkeninin içi boş değilse ekrana bastırmasını ve 1 numaralı çıkış kodunu vermesini istedik. Bu arada 1 numaralı çıkış kodu hatalar için kullanılır. Golang programlarında görmüyoruz ama 0 numaralı çıkış kod da işler yolunda gittiği zaman kullanılır. C dili kodlayan arkadaşlarımız bilir, int main fonksiyonunun sonuna return 0 ibaresi girilir. Buraya kadar olan işlemlerimiz komutun tanımlanması ile ilgiliydi. Çıktımızı okuyabilmemiz için birkaç işlem yapmamız gerekiyor. Ne yazık ki çıktımızı direkt olarak değişkene atayıp ekrana bastıramıyoruz. çıktı adında değişkenimizi oluşturuyoruz. Bu değişkenimiz cmdOkuyucu değişkenini taramaya yarayacak. Hemen aşağısında goroutine fonksiyonumuzda çıktı.Scan() döngüsü ile çıktı sonucumuzu ekrana bastırıyoruz. Buraya kadar tanımlamalarımız yapmış bulunduk. Bundan sonra işlemlerimiz komutumuzun çalıştırılması ve sonucun beklenmesi olacak. hata değişkenimize cmd.Start() fonksiyonunu atayarak komut başlatma işleminde hata oluşursa veriyi çekmesini sağladık. Hata var ise error tipindeki hata mesajımızı ekrana ve 1 numaralı hatayı ekrana bastıracak. Son işlemimiz ise komutun sonuçlanmasının beklenmesi. hata değişkenimize cmd.Wait() fonksiyonunu ekleyerek bekleme işleminde oluşabilecek hatanın mesajını çekmiş olduk. Aşağısında eğer hata var ise ekrana bastırması için gerekli kodlarımızı girdik. Son olarak 1 numaralı çıkış işlemini yaptık. Gördüğünüz gibi çıktı alma işlemi biraz daha uzun. Ama mantığını anladıktan sonra kolay bir işlem olduğunu düşüyorum. Örnek 3: Hata Detayı Çekmeden Komut Çıktısı Alma Eğer ben hata çıktısının detayını almak istemiyorum, benim işim sadece çıktıyla diyorsanız yapacağımız işlemler gerçekten kolaylaşıyor. Hemen kodlarımızı görelim.

package main
import (
"fmt"
"log"
"os/exec"
)
func main() {
cmd := exec.Command("go", "versison")
çıktı, hata := cmd.CombinedOutput()
if hata != nil {
log.Fatalf("Komut hatası: %s\n", hata)
}
fmt.Printf(string(çıktı))
}

Kodlarımızın açıklamasına geçelim. cmd adında değişkenimizde exec.Command() fonksiyonu ile komutlarımızı tanımladık. çıktı ve hata değişkenimize komut çıktılarımızı aldık. Burada hata değişkeni sadece hata numarasını verecektir. Detayları barındırmaz. Eğer hatamız var ise ekrana bastırmasını istedik. Aşağısında ise çıktı değişkenimiz byte dizisi tipinde olduğu için string‘e çevirip ekrana bastırdık.