मुख्य सामग्री पर जाएं
मॉड्यूल 10 · पाठ 4 का 5पाठ्यक्रम में 49/50~18 min
मॉड्यूल पाठ (4/5)

मिनी-प्रोजेक्ट: झंडों के साथ एक सीएलआई

आइए एक छोटी मुहावरेदार 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 को छोड़ देता है।

स्टडर बनाम स्टडआउट

पुराना और पवित्र यूनिक्स नियम:

  • 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

आधुनिक ऐप्स (गो 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
}

लाभ:

  • परीक्षण योग्य: आप bytes.Buffer को stdout/stderr के रूप में पास करते हैं और आउटपुट को सत्यापित करते हैं।
  • कोई वैश्विक स्थिति नहीं: प्रत्येक FlagSet पृथक है।
  • main छोटा रहता है: यह IO + प्रतिनिधियों को तैयार करता है।

उपआदेश

उपकमांड (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लोड हो रहा है...

ध्वज की परिभाषा - डिफ़ॉल्ट 1 के वास्तविक मूल्य का विवरण और 'रिपेटिज़ोनी' का वर्णन, ध्वज को पार्स() और मूल्य के अनुसार चिह्नित करें।

संपादक लोड हो रहा है...

3 प्रयासों के बाद समाधान उपलब्ध है

व्यायाम#go.m10.l4.e2
प्रयास: 0लोड हो रहा है...

यदि आप फ़्लैग.पार्से में कोई स्थिति प्राप्त नहीं करना चाहते हैं, तो यह सुनिश्चित करें कि आप ओएस.एग्जिट(1) पर स्थिर और समाप्त हो गए हैं।

संपादक लोड हो रहा है...

3 प्रयासों के बाद समाधान उपलब्ध है

Quiz#go.m10.l4.e3
तैयार

सीएलआई यूनिक्स-अनुकूल में त्रुटिपूर्ण और उपयोग योग्य स्ट्रीम स्टैम्पी क्या है?

Go
fmt.Fprintln(???, "uso: prog ...")
उत्तर विकल्प