ప్రధాన కంటెంట్‌కు వెళ్లండి
మాడ్యూల్ 10 · 5లో పాఠం 4కోర్సులో 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, _AGYTOK_INLINE_INLINE
  • 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 vs Stdout

పాత మరియు పవిత్రమైన Unix నియమం:

  • 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 vs fmt

  • fmt వినియోగదారు అవుట్‌పుట్ కోసం.
  • log డయాగ్నస్టిక్స్ కోసం: టైమ్‌స్టాంప్‌ని జోడిస్తుంది, డిఫాల్ట్‌గా os.Stderrకి వ్రాస్తుంది, log.Fatal (లాగ్‌లు + os.Exit(1)) మరియు AGYTOK_34INLINEINLINE
Go
log.SetFlags(log.LstdFlags | log.Lshortfile) // timestamp + file:line
log.Fatal("boom") // prints and exits with 1

ఆధునిక యాప్‌ల కోసం (1.21+ వెళ్లండి) నిర్మాణాత్మక లాగింగ్ కోసం **log/slog**ని ఉపయోగించండి (JSON లేదా టెక్స్ట్, లెవెల్‌లు, టైప్ చేసిన ఫీల్డ్‌లు).

ఆర్కిటెక్చర్: లాజిక్ నుండి 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 + డెలిగేట్‌లను సిద్ధం చేస్తుంది.

ఉపకమాండ్లు

సబ్‌కమాండ్‌లతో కూడిన 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 posizionale dopo flag.parse, stamp 'manca argomento' su Stderr e termina con os.Exit(1).

ఎడిటర్ లోడ్ అవుతోంది…

3 ప్రయత్నాల తర్వాత పరిష్కారం లభిస్తుంది

Quiz#go.m10.l4.e3
సిద్ధంగా ఉంది

CLI యూనిక్స్-ఫ్రెండ్లీలో క్వలే స్ట్రీమ్ స్టాంపి మెస్సాగి డి తప్పు మరియు యూసేజ్?

Go
fmt.Fprintln(???, "uso: prog ...")
సమాధాన ఎంపికలు