Buyruq qatori dasturlari va standart oqimlar
Buyruq qatori interfeysi (CLI) terminaldan argument qabul qilib, natijani yana terminalga chiqaradigan dasturdir. Go’ning os va flag paketlari kichik CLI dasturlarini tashqi kutubxonasiz yozishga yordam beradi.
os.Args bilan argument olish
os.Args — dasturga berilgan argumentlarni saqlovchi []string. Birinchi element har doim ishga tushirilgan dastur nomi yoki yo‘li bo‘ladi:
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("Dastur:", os.Args[0])
fmt.Println("Argumentlar:", os.Args[1:])
}
go run ishlatilganda os.Args[0] vaqtinchalik bajariladigan fayl yo‘li bo‘lishi mumkin. Shu sabab dastur mantig‘ini aniq fayl nomiga bog‘lamang. os.Args[1:] esa foydalanuvchi bergan argumentlarni qaytaradi.
flag paketi
flag nomlangan parametrlarni e’lon qilish, tekshirish va yordam matnini chiqarishni soddalashtiradi:
name := flag.String("name", "mehmon", "foydalanuvchi nomi")
count := flag.Int("count", 1, "takrorlash soni")
quiet := flag.Bool("quiet", false, "natijani chiqarmaslik")
flag.Parse()
String, Int va Bool funksiyalari qiymatga ko‘rsatkich qaytaradi. flag.Parse() argumentlarni tahlil qilgandan keyin *name, *count va *quiet orqali qiymat olinadi. flag.Args() esa flaglardan keyin qolgan pozitsion argumentlarni beradi.
Standart oqimlar
Jarayonda uchta standart oqim mavjud:
os.Stdin— kirish ma’lumoti;os.Stdout— odatiy natija;os.Stderr— xato va diagnostika xabarlari.
Oddiy natijani stdout’ga, xatoni stderr’ga yozish shell orqali ularni alohida yo‘naltirish imkonini beradi:
fmt.Println() odatda stdout’ga yozadi. Terminaldan matn o‘qish uchun fmt.Fscan(os.Stdin, &value) yoki bufio.NewScanner(os.Stdin) ishlatilishi mumkin.
Exit code
Dastur muvaffaqiyatli tugasa, odatda 0 exit code qaytaradi. Nol bo‘lmagan qiymat xatoni bildiradi. os.Exit(code) jarayonni darhol to‘xtatadi.
Warning
os.Exit() chaqirilganda defer bilan rejalashtirilgan funksiyalar bajarilmaydi. Tozalash ishlarini run() kabi alohida funksiyada bajaring, os.Exit()ni esa main()da yakuniy natija uchun chaqiring.
Ishlaydigan CLI misoli
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))
}
run() argumentlar va oqimlarni parametr sifatida olgani uchun uni test qilish oson. Flag sintaksisi xatosi uchun 2, noto‘g‘ri qiymat uchun 1, muvaffaqiyat uchun 0 qaytarildi.
Xulosa
os.Args barcha argumentlarni beradi, flag esa nomlangan parametrlarni tahlil qiladi. Natija va xatoni tegishlicha stdout hamda stderr’ga yozing. os.Exit()ni defer ishlaydigan funksiyalardan tashqarida, jarayonning yakuniy chegarasida chaqiring.
Misollar
1. Birinchi pozitsion argumentni olish
Bu misolda dastur nomidan keyingi birinchi argument foydalanuvchi nomi sifatida olinadi.
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)
}
os.Args[0] dastur nomi yoki yo‘lini saqlaydi. Shu sabab foydalanuvchining birinchi argumenti 1-indeksda turadi. len(os.Args) < 2 tekshiruvi argument berilmaganda mavjud bo‘lmagan indeksga murojaat qilishning oldini oladi.
2. Barcha pozitsion argumentlarni ko‘rish
Bu misolda dasturga berilgan argumentlar tartib raqami bilan chiqariladi.
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)
}
}
os.Args[1:] dastur nomini tashlab, faqat foydalanuvchi argumentlarini oladi. Slice indeksi 0 dan boshlanadi, lekin foydalanuvchiga tartib raqami 1 dan ko‘rsatilishi uchun index+1 chiqariladi.
3. Flag uchun standart qiymat belgilash
Bu misolda -name va -count berilmasa, oldindan belgilangan qiymatlar ishlatiladi.
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)
}
}
countning standart qiymati 1, chunki salomlashish kamida bir marta bajarilishi kerak. Sikl indeksi 0 dan boshlanadi va i < *count sharti aynan count marta ishlaydi. flag.Parse()dan keyin ko‘rsatkichlar orqali yakuniy qiymatlar olinadi.
4. Mantiqiy flag va qolgan argumentlar
Bu misolda -upper mantiqiy flagi va undan keyingi pozitsion argumentlar alohida olinadi.
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())
}
false standart qiymati rejim o‘zi yoqilmasligini bildiradi. Foydalanuvchi -upper yozsa, qiymat true bo‘ladi. flag.Args() tahlil qilingan flaglardan keyin qolgan argumentlarni slice sifatida qaytaradi.
5. Qiymatni mavjud o‘zgaruvchiga yozish
Bu misolda flag.StringVar() natijani ko‘rsatkich orqali avval e’lon qilingan o‘zgaruvchiga yozadi.
package main
import (
"flag"
"fmt"
)
func main() {
var city string
flag.StringVar(&city, "city", "Toshkent", "shahar nomi")
flag.Parse()
fmt.Println("Shahar:", city)
}
city dastlab string turning nol qiymati, ya’ni bo‘sh matn bilan yaratiladi. StringVar()ga &city beriladi va flag.Parse() uning qiymatini flag yoki standart Toshkent qiymati bilan yangilaydi. Bu usul alohida *string o‘zgaruvchisini saqlashni talab qilmaydi.
6. Faqat aniq berilgan flaglarni ko‘rish
Bu misolda flag.Visit() foydalanuvchi buyruqda yozgan flaglarni sanab o‘tadi.
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())
})
}
flag.Visit() faqat buyruq qatorida aniq yozilgan flaglar uchun funksiyani chaqiradi. Standart qiymatda qolgan flaglar ro‘yxatga kirmaydi. Masalan, -name Ali -quiet berilsa, faqat name va quiet chiqariladi.
7. Standart kirishdan bitta qiymat o‘qish
Bu misolda fmt.Fscan() stdindan mahsulot nomini o‘qiydi.
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)
}
product dastlab bo‘sh matn. Fscan() qiymatni &product manziliga yozadi. Oddiy natija os.Stdoutga, o‘qish xatosi esa os.Stderrga yuboriladi. Dasturga echo daftar | go run main.go ko‘rinishida ma’lumot uzatish mumkin.
8. Standart kirishni satrma-satr o‘qish
Bu misolda bufio.Scanner stdindan kelgan har bir satrni alohida chiqaradi.
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)
}
}
lineNumber foydalanuvchiga ko‘rsatiladigan birinchi satr raqami bo‘lgani uchun 1 dan boshlanadi. Scanner.Scan() keyingi satr bo‘lsa true, oqim tugasa false qaytaradi. Sikldan keyin scanner.Err() oqim xato sababli to‘xtaganini tekshiradi.
9. Natija va xatoni alohida oqimlarga yozish
Bu misolda argument mavjud bo‘lsa natija stdoutga, mavjud bo‘lmasa foydalanish xabari stderrga yoziladi.
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:]))
}
run() muvaffaqiyat uchun 0, argument yetishmasa 1 qaytaradi. main() exit codeni os.Exit()ga beradi. os.Args[1:] faqat foydalanuvchi argumentlarini uzatadi. Misolni go run main.go salom deb ishga tushirganda muvaffaqiyatli tugaydi.
10. Alohida FlagSet bilan CLI yozish
Bu misolda argumentlar va chiqish oqimlari run() funksiyasiga 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)
}
flag.NewFlagSet() global flaglardan mustaqil tahlilchi yaratadi. flag.ContinueOnError sintaksis xatosida jarayonni o‘zi to‘xtatmaydi; run() 2 codeni qaytaradi. Standart ism mehmon, shu sabab -name berilmasa ham dastur muvaffaqiyatli ishlaydi.