Buyruq qatori dasturlari va standart oqimlar
Buyruq qatori interfeysi, ya’ni CLI (Command Line Interface) — terminal orqali boshqariladigan dastur.
Bunday dastur odatda:
- terminaldan argument qabul qiladi;
- kerak bo‘lsa
stdinorqali qo‘shimcha ma’lumot o‘qiydi; - natijani
stdoutga chiqaradi; - xato va diagnostika xabarlarini
stderrga yozadi; - ish tugaganda exit code qaytaradi.
Go’da kichik va o‘rta CLI dasturlarini tashqi kutubxonalarsiz ham yozish mumkin. Buning uchun standard library ichidagi os, flag, fmt, bufio va io kabi paketlar yetarli bo‘ladi.
Masalan, quyidagi buyruqda:
olma va anor — dasturga berilgan argumentlar.
Yoki:
bu yerda -name va -count — nomlangan parametrlar, ya’ni flaglar.
Endi bu ma’lumotlar Go dasturi ichida qanday olinishi va ishlatilishini bosqichma-bosqich ko‘ramiz.
os.Args bilan argument olish
Go dasturiga buyruq qatori orqali berilgan barcha argumentlar os.Args ichida saqlanadi.
os.Args turi:
ya’ni bu string qiymatlardan iborat slice.
Muhim qoida shuki, os.Args[0] foydalanuvchi bergan birinchi argument emas. Birinchi element odatda ishga tushirilgan dastur nomi yoki uning yo‘lini saqlaydi.
Masalan:
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("Dastur:", os.Args[0])
fmt.Println("Argumentlar:", os.Args[1:])
}
Dasturni quyidagicha ishga tushiramiz:
Bu yerda taxminan quyidagi holat hosil bo‘ladi:
os.Args[0] -> bajarilayotgan dastur yo‘li
os.Args[1] -> "olma"
os.Args[2] -> "anor"
os.Args[1:] -> ["olma", "anor"]
os.Args[1:] slice expression hisoblanadi. U 0-indeksdagi dastur nomini tashlab, foydalanuvchi bergan argumentlarni qaytaradi.
go run bilan ishlaganda yana bir nozik jihat bor. Go avval vaqtinchalik executable fayl yaratib, keyin uni ishga tushiradi. Shu sabab:
qiymati main.go bo‘lishi shart emas. U vaqtinchalik executable fayl yo‘li bo‘lishi mumkin.
Shuning uchun dastur mantig‘ini os.Args[0]ning aniq qiymatiga bog‘lash yaxshi yondashuv emas.
Masalan, bunday tekshiruvdan qochish kerak:
Chunki compiled binary yoki go run holatida bu qiymat boshqacha bo‘lishi mumkin.
os.Args oddiy pozitsion argumentlar uchun juda qulay. Lekin -name, -count, -quiet kabi nomlangan parametrlar ko‘payganda ularni qo‘lda tahlil qilish noqulaylashadi. Bunday vaziyatda flag paketi foydali.
flag paketi
flag paketi buyruq qatori flaglarini e’lon qilish va tahlil qilishni soddalashtiradi.
Masalan:
name := flag.String("name", "mehmon", "foydalanuvchi nomi")
count := flag.Int("count", 1, "takrorlash soni")
quiet := flag.Bool("quiet", false, "natijani chiqarmaslik")
flag.Parse()
Bu yerda uchta flag e’lon qilindi:
Ularni quyidagicha ishlatish mumkin:
Har bir e’lonni alohida ko‘ramiz.
flag.String() uchta asosiy argument oladi:
Natijada funksiya *string, ya’ni stringga pointer qaytaradi.
Shu sabab keyin qiymatni olish uchun:
deb yoziladi.
Xuddi shu qoida flag.Int() va flag.Bool() uchun ham amal qiladi:
count := flag.Int("count", 1, "takrorlash soni")
quiet := flag.Bool("quiet", false, "natijani chiqarmaslik")
Bu qiymatlarning turlari:
Lekin flaglarni faqat e’lon qilish yetarli emas.
chaqirilganda flag paketi haqiqiy buyruq qatori argumentlarini tahlil qiladi va tegishli qiymatlarni yangilaydi.
Masalan:
bo‘lsa, flag.Parse()dan keyin:
bo‘ladi.
quiet buyruqda berilmagani uchun uning standart qiymati false saqlanadi.
Pozitsion argumentlar va flag.Args()
Flaglar bilan birga oddiy argumentlar ham ishlatilishi mumkin.
Masalan:
flag.Parse()dan keyin flag bo‘lmagan qolgan argumentlarni:
orqali olish mumkin.
Taxminan:
Bu usul flaglar va pozitsion argumentlarni birgalikda ishlatadigan CLI dasturlarda foydali.
Standart oqimlar
Operatsion tizim ishga tushirilgan jarayon uchun odatda uchta standart oqim taqdim etadi:
os.Stdin— standart kirish;os.Stdout— standart chiqish;os.Stderr— standart xato oqimi.
Bu uchta oqim bir-biridan alohida.
Oddiy holatda terminalda ularning natijasi bir joyda ko‘rinishi mumkin. Lekin shell orqali ularni alohida fayllarga yoki boshqa jarayonlarga yo‘naltirish mumkin.
os.Stdin
os.Stdin dasturga kiruvchi ma’lumot oqimi.
Masalan, foydalanuvchi terminalda matn yozishi mumkin. Yoki boshqa dastur pipe orqali ma’lumot yuborishi mumkin.
Go’da undan quyidagicha o‘qish mumkin:
yoki satrma-satr o‘qish uchun:
os.Stdout
os.Stdout odatiy natijalar uchun ishlatiladi.
Masalan:
fmt.Println() ham odatda stdout’ga yozadi.
Shuning uchun:
va:
oddiy holatda terminalda bir xil natija beradi.
Ikkinchi variantning afzalligi shuki, qaysi io.Writerga yozilayotgani aniq ko‘rinadi. Bu test yozishda ham qulay.
os.Stderr
os.Stderr xato va diagnostika xabarlari uchun ishlatiladi.
Masalan:
Nega xatoni oddiy stdoutga yozmaymiz?
Sababi stdout va stderrni shell orqali alohida boshqarish mumkin.
Masalan, dastur natijasini faylga yozib:
xato xabarlarini esa terminalda qoldirish mumkin.
Yoki xatolarni alohida faylga yuborish mumkin:
Bu ayniqsa scriptlar, serverlar va boshqa dasturlar bilan ulanadigan CLI vositalarida muhim.
Dastur muvaffaqiyatli natijani stdoutga, xatoni esa stderrga yozsa, tashqi dastur ularni bir-biridan farqlay oladi.
Masalan:
Bu ikkala yozuv terminalda ko‘rinishi mumkin, lekin ular turli oqimlarga yozilgan.
Exit code
CLI dastur faqat matn chiqarmaydi. Jarayon tugaganda operatsion tizimga raqamli exit code ham qaytaradi.
Odatda:
Masalan, shell script quyidagi buyruq muvaffaqiyatli tugagan-tugamaganini exit code orqali aniqlashi mumkin.
Go’da jarayonni ma’lum code bilan tugatish uchun:
ishlatiladi.
Masalan:
muvaffaqiyatli tugashni, quyidagisi esa:
xatoni bildirishi mumkin.
Aniq non-zero qiymatlarning ma’nosini dastur muallifi belgilaydi.
Masalan:
kabi kelishuv qilish mumkin.
os.Exit() va defer
Bu yerda muhim bir nozik holat bor.
Warning
os.Exit() chaqirilganda defer orqali rejalashtirilgan funksiyalar bajarilmaydi.
Masalan:
```go func main() { defer fmt.Println("Tozalash")
os.Exit(1)
}
Bu yerda:
```text Tozalash
chiqishi kutilgandek ko‘rinishi mumkin. Lekin os.Exit() jarayonni darhol tugatadi. Shu sabab defer ishlamaydi.
Bu file yopish, buffer flush qilish, temporary resurslarni tozalash yoki boshqa cleanup ishlari uchun muammo tug‘dirishi mumkin.
Shuning uchun keng tarqalgan yondashuv quyidagicha:
```go func run() int { // Asosiy ishlar. // defer ishlatish mumkin.
return 0
}
func main() { os.Exit(run()) }
Bu yerda barcha asosiy ishlar run() ichida bajariladi.
run() oddiy funksiya bo‘lgani uchun undan chiqishda deferlar normal ishlaydi.
Faqat eng oxirida main():
```go os.Exit(...)
orqali jarayonning exit codeni belgilaydi.
Ishlaydigan CLI misoli
Endi argumentlar, flaglar, stdout, stderr va exit codelarni bitta dastur ichida birlashtiramiz.
package main
import (
"errors"
"flag"
"fmt"
"io"
"os"
)
func run(args []string, stdout, stderr io.Writer) int {
fs := flag.NewFlagSet("salom", flag.ContinueOnError)
fs.SetOutput(stderr)
name := fs.String("name", "", "salomlashiladigan ism")
count := fs.Int("count", 1, "takrorlash soni")
quiet := fs.Bool("quiet", false, "natijani chiqarmaslik")
if err := fs.Parse(args); err != nil {
return 2
}
if *name == "" {
fmt.Fprintln(stderr, errors.New("-name parametri kerak"))
return 1
}
if *count < 1 {
fmt.Fprintln(stderr, "xato: -count musbat bo‘lishi kerak")
return 1
}
if *quiet {
return 0
}
for i := 0; i < *count; i++ {
fmt.Fprintf(stdout, "Salom, %s!\n", *name)
}
return 0
}
func main() {
os.Exit(run(os.Args[1:], os.Stdout, os.Stderr))
}
Dasturni quyidagicha ishga tushiramiz:
Natija:
Bu misolda bir nechta muhim qaror bor.
Birinchisi:
run() global os.Args, os.Stdout va os.Stderrga to‘g‘ridan-to‘g‘ri bog‘lanmagan.
U argumentlarni parametr orqali oladi:
Chiqish oqimlari ham parametr orqali uzatiladi:
Bu test yozishni ancha osonlashtiradi. Test vaqtida haqiqiy terminal o‘rniga bytes.Buffer berish mumkin.
Masalan, stdout o‘rniga xotiradagi buffer berib, dastur aynan qanday matn yozganini tekshirish mumkin.
Keyingi muhim qism:
Bu global flag paketidagi default flaglar o‘rniga alohida FlagSet yaratadi.
flag.ContinueOnError flag parsing vaqtida xato bo‘lsa, jarayonni avtomatik tugatib yubormaydi. Xato fs.Parse()dan qaytadi:
Bu CLI dasturga xato qanday boshqarilishini o‘zi nazorat qilish imkonini beradi.
Keyin:
FlagSet tomonidan chiqariladigan xato va yordam matnlarini biz bergan stderr oqimiga yo‘naltiradi.
-name uchun standart qiymat bo‘sh string:
Shuning uchun keyin uning berilgan-berilmaganini tekshirish mumkin:
count qiymati ham tekshiriladi:
Bu yerda flag sintaksisi to‘g‘ri bo‘lishi mumkin, lekin qiymat biznes qoidasi uchun noto‘g‘ri bo‘lishi mumkin.
Masalan:
-5 int sifatida o‘qilishi mumkin. Lekin dastur talabi bo‘yicha takrorlash soni kamida 1 bo‘lishi kerak. Shu sabab bu alohida validatsiya qilinadi.
quiet yoqilgan bo‘lsa:
dastur hech qanday salomlashish chiqarmaydi, lekin muvaffaqiyatli tugaydi.
Aks holda sikl:
count marta natija chiqaradi.
Oxirida:
muvaffaqiyatni bildiradi.
main() esa:
orqali uchta haqiqiy qiymatni run()ga uzatadi:
run() qaytargan son esa jarayonning exit code’iga aylanadi.
Bu strukturada:
qaytariladi.
Misollar
1. Birinchi pozitsion argumentni olish
Bu misol os.Args orqali foydalanuvchi bergan birinchi pozitsion argumentni olishni ko‘rsatadi.
Dastur argumentni ism sifatida ishlatadi.
package main
import (
"fmt"
"os"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("Foydalanish: dastur ISM")
return
}
name := os.Args[1]
fmt.Println("Salom,", name)
}
Bu yerda eng muhim qism:
os.Args ichida kamida bitta element deyarli har doim mavjud bo‘ladi:
u dastur nomi yoki yo‘li.
Foydalanuvchi argument bergan bo‘lsa, u:
da turadi.
Shuning uchun os.Args[1]ga murojaat qilishdan oldin slice uzunligi kamida 2 ekanini tekshiramiz.
Agar bu tekshiruv bo‘lmasa va foydalanuvchi argument bermasa:
mavjud bo‘lmagan indeksga murojaat qiladi va dastur runtime vaqtida panic qilishi mumkin.
Argument berilganda:
natija:
bo‘ladi.
Bu misolning asosiy qoidasi: os.Args[0] dasturga tegishli, foydalanuvchining birinchi argumenti esa os.Args[1]da turadi.
2. Barcha pozitsion argumentlarni ko‘rish
Bu misol foydalanuvchi bergan barcha pozitsion argumentlarni tartib raqami bilan chiqaradi.
package main
import (
"fmt"
"os"
)
func main() {
args := os.Args[1:]
if len(args) == 0 {
fmt.Println("Argument berilmadi")
return
}
for index, value := range args {
fmt.Printf("%d: %s\n", index+1, value)
}
}
Avval:
orqali dastur nomini tashlab yuboramiz.
Masalan:
bo‘lsa:
bo‘ladi.
Keyin:
orqali foydalanuvchi umuman argument berganmi yoki yo‘qmi, tekshiriladi.
Argumentlar bo‘lsa:
slice elementlari bo‘ylab yuriladi.
rangedagi index 0dan boshlanadi:
Lekin foydalanuvchiga tartib raqamini odatda 1dan boshlab ko‘rsatish qulayroq. Shu sabab:
ishlatiladi.
Natija:
bo‘ladi.
Bu misolda slice indeksi bilan foydalanuvchiga ko‘rsatiladigan tartib raqami bir xil narsa emasligini ko‘rish mumkin.
3. Flag uchun standart qiymat belgilash
Bu misolda -name va -count flaglari uchun standart qiymatlar belgilanadi.
Agar foydalanuvchi flaglarni bermasa, dastur shu qiymatlarni ishlatadi.
package main
import (
"flag"
"fmt"
)
func main() {
name := flag.String("name", "mehmon", "foydalanuvchi nomi")
count := flag.Int("count", 1, "takrorlash soni")
flag.Parse()
for i := 0; i < *count; i++ {
fmt.Println("Salom,", *name)
}
}
Bu yerda:
-name berilmasa:
bo‘ladi.
Xuddi shunday:
sababli -count berilmasa:
bo‘ladi.
Shu sabab:
natijasi:
bo‘ladi.
Agar:
deb ishga tushirilsa, natija:
bo‘ladi.
Siklni ko‘ramiz:
Agar count = 3 bo‘lsa:
Natijada kod aynan uch marta bajariladi.
countning standart qiymati 1 bo‘lishi bu misolda mantiqan qulay. Foydalanuvchi hech narsa bermasa ham dastur kamida bir marta salomlashadi.
4. Mantiqiy flag va qolgan argumentlar
Bu misolda bool flag va undan tashqari qolgan pozitsion argumentlarni olish ko‘rsatiladi.
package main
import (
"flag"
"fmt"
)
func main() {
upper := flag.Bool("upper", false, "katta harf rejimini yoqish")
flag.Parse()
fmt.Println("Katta harf rejimi:", *upper)
fmt.Println("Qolgan argumentlar:", flag.Args())
}
upper uchun standart qiymat:
Bu rejim odatda o‘chiq ekanini bildiradi.
Agar foydalanuvchi:
deb ishga tushirsa:
ko‘rinishidagi natija hosil bo‘ladi.
Agar:
deb ishga tushirilsa:
bo‘ladi.
flag.Parse() -upperni flag sifatida tahlil qiladi.
Qolgan:
argumentlari esa:
orqali olinadi.
Natija taxminan:
bo‘ladi.
Bu misol flaglar va pozitsion argumentlarni bitta CLI ichida qanday ajratish mumkinligini ko‘rsatadi.
5. Qiymatni mavjud o‘zgaruvchiga yozish
flag.String() yangi *string qiymat qaytaradi.
Ba’zan esa qiymatni oldindan e’lon qilingan o‘zgaruvchiga yozish qulayroq bo‘ladi. Buning uchun flag.StringVar() mavjud.
package main
import (
"flag"
"fmt"
)
func main() {
var city string
flag.StringVar(&city, "city", "Toshkent", "shahar nomi")
flag.Parse()
fmt.Println("Shahar:", city)
}
Avval:
yoziladi.
string turning zero value’i bo‘sh string:
Keyin:
chaqiriladi.
Bu yerda &city — city o‘zgaruvchisining manzili.
flag paketi parsing vaqtida qiymatni shu o‘zgaruvchining o‘ziga yozadi.
Agar foydalanuvchi:
deb ishga tushirsa, standart qiymat ishlatiladi:
Agar:
bo‘lsa:
chiqadi.
flag.String() bilan yozilganda:
va keyin:
ishlatish kerak bo‘lardi.
StringVar() esa mavjud o‘zgaruvchini yangilaydi. Shu sabab keyin to‘g‘ridan-to‘g‘ri:
ishlatiladi.
6. Faqat aniq berilgan flaglarni ko‘rish
Ba’zan dasturda qaysi flaglar foydalanuvchi tomonidan haqiqatan ham yozilganini bilish kerak bo‘ladi.
Standart qiymat mavjud bo‘lishi flag buyruqda berilganini anglatmaydi.
Bunday vaziyatda flag.Visit() ishlatiladi.
package main
import (
"flag"
"fmt"
)
func main() {
flag.String("name", "mehmon", "foydalanuvchi nomi")
flag.Int("count", 1, "takrorlash soni")
flag.Bool("quiet", false, "jim rejim")
flag.Parse()
fmt.Println("Aniq berilgan flaglar:")
flag.Visit(func(item *flag.Flag) {
fmt.Printf("-%s=%s\n", item.Name, item.Value.String())
})
}
Bu dasturda uchta flag mavjud:
Lekin flag.Visit() ularning barchasini emas, faqat foydalanuvchi buyruqda aniq yozganlarini ko‘radi.
Masalan:
bo‘lsa:
chiqariladi.
count esa:
standart qiymatga ega bo‘lsa ham, buyruqda yozilmagan. Shu sabab flag.Visit() ichiga kirmaydi.
Bu farq konfiguratsiya tizimlarida foydali bo‘lishi mumkin.
Masalan, dasturga qiymat config fayldan, environment variable’dan va CLI flagdan kelishi mumkin. Shunda foydalanuvchi CLI orqali flagni aniq berganmi yoki standart qiymat ishlatilganmi, bilish muhim bo‘lishi mumkin.
7. Standart kirishdan bitta qiymat o‘qish
Bu misolda fmt.Fscan() orqali stdindan bitta qiymat o‘qiladi.
package main
import (
"fmt"
"os"
)
func main() {
var product string
fmt.Fprint(os.Stdout, "Mahsulot nomi: ")
if _, err := fmt.Fscan(os.Stdin, &product); err != nil {
fmt.Fprintln(os.Stderr, "Xato: nom o‘qilmadi")
return
}
fmt.Fprintln(os.Stdout, "Qabul qilindi:", product)
}
Avval:
orqali bo‘sh string yaratiladi.
Keyin:
foydalanuvchiga prompt chiqaradi.
Asosiy o‘qish:
orqali bajariladi.
Bu yerda &product berilishining sababi muhim.
Fscan() o‘qilgan qiymatni product o‘zgaruvchisiga yozishi kerak. Buning uchun unga o‘zgaruvchining manzili kerak.
Agar o‘qish muvaffaqiyatsiz bo‘lsa:
sharti bajariladi va xato:
orqali stderrga yoziladi.
Muvaffaqiyatli holatda:
ishlaydi.
Bu dasturga ma’lumotni terminaldan qo‘lda kiritish mumkin.
Lekin stdin faqat klaviatura degani emas.
Masalan:
buyrug‘ida echo chiqishi pipe orqali keyingi dastur stdiniga uzatiladi.
Oqim taxminan shunday:
Natijada product qiymati:
bo‘ladi.
8. Standart kirishni satrma-satr o‘qish
Ko‘p qatorli input bilan ishlaganda bufio.Scanner qulay.
Bu misolda stdindan kelgan har bir satr tartib raqami bilan chiqariladi.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
lineNumber := 1
for scanner.Scan() {
fmt.Fprintf(os.Stdout, "%d: %s\n", lineNumber, scanner.Text())
lineNumber++
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "O‘qish xatosi:", err)
}
}
Avval:
orqali stdin bilan ishlaydigan scanner yaratiladi.
Standart holatda Scanner inputni satrlar bo‘yicha ajratadi.
Keyin:
birinchi ko‘rsatiladigan satr raqamini belgilaydi.
Sikl:
har safar keyingi satrni o‘qishga harakat qiladi.
Agar keyingi token, bu holatda satr mavjud bo‘lsa:
true qaytaradi.
Keyingi satr matni:
orqali olinadi.
Masalan, input:
bo‘lsa, chiqish:
bo‘ladi.
Har iteratsiyadan keyin:
satr raqamini bittaga oshiradi.
Siklning tugashi har doim xato degani emas.
Input odatiy tarzda tugasa ham Scan() false qaytaradi.
Shuning uchun sikldan keyin:
orqali scanner xato sababli to‘xtaganmi, tekshiriladi.
Bu muhim, chunki faqat Scan() == falsega qarab input tugadimi yoki o‘qish xatosi yuz berdimi, farqlab bo‘lmaydi.
Note
bufio.Scanner juda katta tokenlar uchun standart limitga ega. Juda uzun satrlarni o‘qish kerak bo‘lsa, scanner bufferini kattalashtirish yoki bufio.Reader kabi boshqa usuldan foydalanish kerak bo‘lishi mumkin.
9. Natija va xatoni alohida oqimlarga yozish
Bu misol stdout, stderr va exit codeni birga ishlatishni ko‘rsatadi.
Argument mavjud bo‘lsa natija stdoutga yoziladi.
Argument bo‘lmasa foydalanish xabari stderrga yoziladi va non-zero exit code qaytariladi.
package main
import (
"fmt"
"os"
)
func run(args []string) int {
if len(args) == 0 {
fmt.Fprintln(os.Stderr, "Foydalanish: dastur MATN")
return 1
}
fmt.Fprintln(os.Stdout, "Natija:", args[0])
return 0
}
func main() {
os.Exit(run(os.Args[1:]))
}
main():
orqali dastur nomini chiqarib tashlaydi.
Shuning uchun run() faqat foydalanuvchi argumentlarini oladi.
Agar:
bo‘lsa, foydalanuvchi kerakli argumentni bermagan.
Shunda:
xato yoki foydalanish xabarini stderrga yozadi.
Keyin:
xato holatini bildiradi.
Agar argument mavjud bo‘lsa:
oddiy natijani stdoutga chiqaradi.
So‘ng:
muvaffaqiyatni bildiradi.
Masalan:
chiqishi:
bo‘ladi.
Bu misolda uchta kanal aniq ajratilgan:
CLI dasturlarda bu ajratish foydali. Chunki boshqa dastur stdout’dagi ma’lumotni qayta ishlashi, stderr’dagi diagnostikani esa alohida ko‘rsatishi mumkin.
10. Alohida FlagSet bilan CLI yozish
Bu misolda global flag holatidan foydalanmaymiz.
Argumentlarni tahlil qilish uchun alohida FlagSet yaratiladi. Argumentlar va chiqish oqimlari esa run() funksiyasiga parametr sifatida beriladi.
package main
import (
"flag"
"fmt"
"io"
"os"
)
func run(args []string, stdout, stderr io.Writer) int {
fs := flag.NewFlagSet("greet", flag.ContinueOnError)
fs.SetOutput(stderr)
name := fs.String("name", "mehmon", "foydalanuvchi nomi")
if err := fs.Parse(args); err != nil {
return 2
}
fmt.Fprintln(stdout, "Salom,", *name)
return 0
}
func main() {
code := run(os.Args[1:], os.Stdout, os.Stderr)
os.Exit(code)
}
Asosiy qism:
Bu yangi va mustaqil FlagSet yaratadi.
Global:
o‘rniga endi:
ishlatiladi.
Bu yondashuv ayniqsa testlarda va bir nechta commandga ega dasturlarda qulay.
Masalan, katta CLI ichida:
kabi subcommandlar bo‘lsa, har biri uchun alohida FlagSet yaratish mumkin.
Keyingi qator:
FlagSetning diagnostika va parsing xabarlarini biz bergan stderr oqimiga yo‘naltiradi.
name flagi:
standart qiymat sifatida:
dan foydalanadi.
Shuning uchun:
ham xato emas.
Natija:
bo‘ladi.
Agar:
deb ishga tushirilsa:
chiqadi.
Parsing vaqtida xato yuz bersa:
ishlaydi.
flag.ContinueOnError tanlanganligi sabab FlagSet jarayonni o‘zi tugatmaydi. U xatoni Parse() orqali qaytaradi.
Shu sabab run() xato holatini exit code sifatida boshqara oladi.
Oxirida:
yoziladi.
Bu strukturada main() juda kichik.
Uning vazifasi faqat real operatsion tizim resurslarini run()ga ulash:
va qaytgan exit codeni jarayon natijasiga aylantirish.
Asosiy dastur mantig‘i esa run() ichida qoladi. Shu sabab uni alohida test qilish osonlashadi.