CodeBlanks Logo Icon CodeBlanks

Özet - flag paketi

flag ve os.Args'ı birleştirerek bir CLI aracı yazarsın.

CLI özeti

İyi bir komut satırı aracı: seçenekler için flag (-h ile otomatik yardım), konumsal argümanlar için flag.Args(), alt komutlar için ayrı FlagSet'ler, dosya verilmezse stdin'den okuma, sonuçları stdout'a ve hataları stderr'e yazma, başarıda 0, hatada 1, kullanım hatasında 2 çıkış kodu.

func main() {
    if err := run(os.Args[1:], os.Stdin, os.Stdout); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

Sinyal ve iptal

Uzun çalışan bir araç Ctrl+C ile durdurulduğunda geçici dosyaları temizlemelidir. signal.NotifyContext sinyali context iptaline çevirir:

ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
if err := isle(ctx); errors.Is(err, context.Canceled) {
    fmt.Fprintln(os.Stderr, "iptal edildi")
    os.Exit(130)
}

130, Ctrl+C ile kesilen programlar için geleneksel çıkış kodudur.

Uygulama run fonksiyonu

run(args []string, in io.Reader, out io.Writer) error yaz: -n (int, varsayılan 1) seçeneğini kendi FlagSet'iyle ayrıştırsın, girdinin ilk satırını bufio.Scanner ile okuyup n kez out'a yazsın. run([]string{"-n=2"}, strings.NewReader("go\n"), os.Stdout) ile çağır.

Başlangıç kodu

main.go
package main

import (
    "bufio"
    "flag"
    "fmt"
    "io"
    "os"
    "strings"
)

func main() {
    // buraya yaz
}

Örnek çözüm

main.go
package main

import (
    "bufio"
    "flag"
    "fmt"
    "io"
    "os"
    "strings"
)

func run(args []string, in io.Reader, out io.Writer) error {
    fs := flag.NewFlagSet("tekrar", flag.ContinueOnError)
    n := fs.Int("n", 1, "tekrar sayısı")
    if err := fs.Parse(args); err != nil {
        return err
    }
    sc := bufio.NewScanner(in)
    if !sc.Scan() {
        return sc.Err()
    }
    for i := 0; i < *n; i++ {
        fmt.Fprintln(out, sc.Text())
    }
    return nil
}

func main() {
    if err := run([]string{"-n=2"}, strings.NewReader("go\n"), os.Stdout); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

Beklenen çıktı

go
go

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 <code>run(args, stdin, stdout)</code> deseni neden yaygındır?

  • flag paketi bunu zorunlu tutar
  • Daha az kod gerektirir
  • Aracın tamamı os paketine dokunmadan test edilebilir Doğru cevap
  • Daha hızlı çalışır

Açıklama: Argümanlar, girdi ve çıktı parametre olduğu için testte dilim, strings.Reader ve bytes.Buffer verilir.

2 Seçenekleri listele

Soru
flag.Usage = func() {
    fmt.Fprintln(os.Stderr, "kullanım: app [seçenekler]")
    flag.____()
}
Cevap
flag.Usage = func() {
    fmt.Fprintln(os.Stderr, "kullanım: app [seçenekler]")
    flag.PrintDefaults()
}

Açıklama: PrintDefaults tüm seçenekleri açıklama ve varsayılanlarıyla yazdırır.

3 Grubun özeti

Kavram Anlamı
flag.Int Seçenek tanımı
flag.Args() Konumsal argümanlar
FlagSet Alt komut
os.Exit(2) Kullanım hatası

Orta seviye bölümündeki tüm dersler