মূল কন্টেন্টে যান
মডিউল 10 · 4-এর পাঠ 5কোর্সে 49/50~18 min
মডিউল পাঠ (4/5)

মিনি-প্রকল্প: পতাকা সহ একটি CLI

চলুন আগের মডিউলগুলির বিল্ডিং ব্লকগুলিকে একসাথে রেখে একটি ছোট বাগধারা CLI তৈরি করা যাক: flag প্যাকেজের সাথে পতাকা পার্সিং, অবস্থানগত আর্গুমেন্ট পরিচালনা করা, os.Stderr-এ ত্রুটি, এবং সঠিক প্রস্থান কোড।

flag প্যাকেজ

Go
package main

import (
    "flag"
    "fmt"
    "os"
)

func main() {
    n := flag.Int("n", 1, "number of repetitions")
    upper := flag.Bool("u", false, "print in uppercase")
    flag.Parse()

    args := flag.Args() // remaining positional arguments
    if len(args) < 1 {
        fmt.Fprintln(os.Stderr, "usage: echo [-n N] [-u] <text>")
        os.Exit(2)
    }

    text := args[0]
    if *upper {
        text = strings.ToUpper(text)
    }
    for i := 0; i < *n; i++ {
        fmt.Println(text)
    }
}

মূল পয়েন্ট:

  • flag.Int, flag.String, flag.Bool, flag.Duration (ইত্যাদি) একটি পয়েন্টার প্রদান করুন: আপনি *n, *upper ব্যবহার করেন।
  • flag.Parse() কে অবশ্যই একবার কল করতে হবে, মান পড়ার আগে এবং flag.Args() এর আগে।
  • flag.Args() অবস্থানগত আর্গুমেন্টগুলি ফেরত দেয় (যেগুলি -- এর পরে বা শেষ পতাকার পরে)।
  • গৃহীত ফর্ম: -n 3, -n=3, --n=3। বুলিয়ানস: -u (সত্য), -u=false।

প্রচলিত প্রস্থান কোড

Go
os.Exit(0) // success
os.Exit(1) // generic error
os.Exit(2) // usage error (incorrect flag usage)

শেল এবং স্ক্রিপ্টগুলি এই কোডগুলি আশা করে: তাদের ধারাবাহিকভাবে ব্যবহার করুন। কখনই os.Exit এর সাথে একটি অ-প্রধান গোরুটিন থেকে প্রস্থান করবেন না: এটি log ফ্লাশিং সহ প্রতি defer এড়িয়ে যায়।

Stderr বনাম Stdout

পুরানো এবং পবিত্র ইউনিক্স নিয়ম:

  • os.Stdout → দরকারী আউটপুট, পাইপ-সক্ষম (cli | grep ...)।
  • os.Stderr_ → ডায়াগনস্টিকস, ত্রুটি, অগ্রগতি বার, ব্যবহার।
Go
fmt.Println("result: 42")                   // stdout
fmt.Fprintln(os.Stderr, "error: ...")       // stderr

এইভাবে cli 2>/dev/null শুধুমাত্র ফলাফল দেখায়, cli >out.txt শুধুমাত্র ফলাফল পুনঃনির্দেশ করে এবং ত্রুটিগুলি দৃশ্যমান থাকে৷

log বনাম fmt

  • ব্যবহারকারীর আউটপুটের জন্য fmt।
  • ডায়াগনস্টিকসের জন্য log: একটি টাইমস্ট্যাম্প যোগ করে, ডিফল্টরূপে os.Stderr এ লেখে, এতে log.Fatal (লগ + os.Exit(1)) এবং log.Panic আছে।
Go
log.SetFlags(log.LstdFlags | log.Lshortfile) // timestamp + file:line
log.Fatal("boom") // prints and exits with 1

আধুনিক অ্যাপের জন্য (Go 1.21+) কাঠামোবদ্ধ লগিং (JSON বা টেক্সট, লেভেল, টাইপ করা ক্ষেত্র) এর জন্য log/slog ব্যবহার করুন।

আর্কিটেকচার: লজিক থেকে main আলাদা করুন

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

func run(args []string, stdout, stderr io.Writer) error {
    // here use a new flag.FlagSet instead of the global flag.CommandLine
    fs := flag.NewFlagSet("echo", flag.ContinueOnError)
    fs.SetOutput(stderr)
    n := fs.Int("n", 1, "repetitions")
    if err := fs.Parse(args); err != nil {
        return err
    }
    // ...
    return nil
}

সুবিধা:

  • পরীক্ষাযোগ্য: আপনি stdout/stderr হিসাবে bytes.Buffer পাস করেন এবং আউটপুট যাচাই করেন।
  • কোন বৈশ্বিক রাষ্ট্র নেই: প্রতিটি FlagSet বিচ্ছিন্ন।
  • main ক্ষুদ্র থাকে: এটি IO + প্রতিনিধিদের প্রস্তুত করে।

সাবকমান্ড

সাবকমান্ড সহ CLI-এর জন্য (mycli serve, mycli migrate), কোনো বাহ্যিক নির্ভরতা ছাড়াই একটি স্কিম:

Go
func main() {
    if len(os.Args) < 2 {
        usage()
        os.Exit(2)
    }
    switch os.Args[1] {
    case "serve":
        serveCmd(os.Args[2:])
    case "migrate":
        migrateCmd(os.Args[2:])
    default:
        usage()
        os.Exit(2)
    }
}

প্রতিটি সাবকমান্ডের নিজস্ব flag.NewFlagSet আছে। বড় প্রকল্পগুলির জন্য, cobra বা urfave/cli এর মতো লাইব্রেরিগুলি স্বয়ংক্রিয়ভাবে তৈরি সাহায্যে এই স্কিমটি গঠন করে৷

ব্যায়াম

ব্যায়াম#go.m10.l4.e1
প্রচেষ্টা: 0লোড হচ্ছে...

Definisci il flag -n di tipo int con valore di default 1 e descrizione 'ripetizioni', poi chiama flag.Parse() e stampa il valore.

সম্পাদক লোড হচ্ছে...

সমাধান 3 প্রচেষ্টার পরে উপলব্ধ

ব্যায়াম#go.m10.l4.e2
প্রচেষ্টা: 0লোড হচ্ছে...

Se non c'è almeno un argomento positional dopo flag.Parse, Stampa 'manca argomento' su Stderr e termina con os.Exit(1)।

সম্পাদক লোড হচ্ছে...

সমাধান 3 প্রচেষ্টার পরে উপলব্ধ

Quiz#go.m10.l4.e3
প্রস্তুত

সু কোয়ালে স্ট্রিম স্ট্যাম্পি মেসেজ ডি ইরর ই ইউসেজ সিএলআই ইউনিক্স-বান্ধব?

Go
fmt.Fprintln(???, "uso: prog ...")
উত্তরের বিকল্প