os.Args
os.Args adalah slice berisi string. os.Args[0] adalah nama program, sisanya adalah argumen persis seperti yang dikirim shell.
Di panel Argumen pada editor, setiap kolom adalah satu argumen yang dikirim apa adanya. Coba hello, two words, dan -v di tiga kolom: program melihat tiga argumen, dan two words tetap satu argumen dengan spasi di dalamnya. Di terminal, shell yang memecah argumen, jadi hal yang sama ditulis go run . hello "two words" -v.
Selalu periksa len(os.Args) sebelum mengakses indeksnya. os.Args[1] tanpa argumen akan panic dengan index out of range [1] with length 1.
Argumen berupa string. Konversi angka dengan strconv.Atoi atau strconv.ParseFloat dan tangani error-nya, karena pengguna bisa mengetik apa saja.
Package flag
Untuk opsi seperti -port 8080 -verbose, pakai flag. Package ini mem-parse, mengonversi tipe, melaporkan error, dan membuat pesan bantuan.
Tanpa argumen, program ini mencetak hello, world sekali. Di panel Argumen, coba -name dan Gopher di dua kolom, lalu -count=3, -loud, dan extra di tiga kolom berikutnya. Program mencetak HELLO, GOPHER! tiga kali dan remaining args: [extra].
Cara kerja flag:
- Setiap fungsi pendefinisi (
flag.String,flag.Int,flag.Bool,flag.Float64,flag.Duration,flag.Uint64...) menerima nama, nilai default, dan teks penjelasan, lalu mengembalikan pointer. Baca nilainya dengan*namesetelahflag.Parse(). - Bentuk
Varmengikat ke variabel yang sudah kamu punya:flag.IntVar(&cfg.Port, "port", 8080, "port"). Cara ini lebih rapi untuk struct konfigurasi. - Pengguna bisa menulis
-name value,-name=value,--name value, atau--name=value. Go tidak membedakan satu atau dua tanda minus. - Boolean butuh
=untuk menerima nilai.-loudmengisi true,-loud=falsemengisi false, tetapi-loud falsemengisi true dan membiarkanfalsesebagai argumen posisional. - Parsing berhenti di argumen pertama yang bukan flag (atau di
--).prog file.txt -vmemperlakukan-vsebagai argumen posisional. Taruh flag di depan. flag.Args()mengembalikan argumen posisional yang tersisa,flag.NArg()jumlahnya, danflag.Arg(i)salah satunya.
Flag yang tidak dikenal atau nilai yang salah akan mencetak error beserta teks bantuan, lalu keluar dengan status 2. -h atau -help mencetak teks bantuan dan keluar dengan status 0 (sejak Go 1.15). Teks bantuan dibuat dari definisi yang kamu tulis:
Usage of greet:
-count int
how many times (default 1)
-delay duration
pause between greetings, e.g. 10ms
-loud
shout the greeting
-name string
who to greet (default "world")
Isi flag.Usage dengan sebuah fungsi untuk mencetak judulmu sendiri sebelum memanggil flag.PrintDefaults().
Subcommand dengan FlagSet
Tool seperti git commit -m msg punya subcommand dengan flag masing-masing. Buat satu flag.FlagSet per subcommand dan pilih salah satunya dengan switch pada argumen pertama:
flag.ContinueOnError membuat Parse mengembalikan error alih-alih keluar dari program, sehingga fungsinya tetap bisa diuji. run menerima argumen sebagai parameter, bukan membaca os.Args, jadi sebuah test bisa langsung memanggil run([]string{"list", "-all"}). Coba list dan -all di panel Argumen, atau delete untuk melihat jalur error-nya.
Untuk CLI besar dengan perintah bertingkat, shell completion, dan dokumentasi yang dibuat otomatis, kebanyakan proyek memakai library pihak ketiga github.com/spf13/cobra. Package standar flag sudah cukup baik untuk tool kecil.
Environment variable
os.Getenvmengembalikan""baik saat variabelnya tidak ada maupun saat diset ke string kosong.os.LookupEnvmembedakan keduanya.- Nilainya selalu string. Konversi dan validasi saat program mulai, dan gagal dengan pesan yang jelas, bukan di tengah-tengah sebuah request.
os.Setenvmemengaruhi proses saat ini dan proses anak yang dijalankan kemudian. Fungsi ini tidak bisa mengubah environment shell yang menjalankan programmu.os.Environ()mengembalikan semua variabel sebagai string"KEY=value".
Susunan yang umum untuk konfigurasi: flag untuk hal yang diketik orang, environment variable untuk pengaturan deployment (platform container mengisinya), dengan flag mengalahkan environment dan environment mengalahkan nilai default.
Exit code dan os.Exit
Program Go keluar dengan status 0 saat main selesai. os.Exit(code) langsung mengakhiri proses dengan status tersebut. Menurut konvensi, 0 berarti berhasil, 1 error umum, dan 2 error pemakaian (package flag memakai 2).
os.Exit tidak menjalankan fungsi yang ditunda. File tidak di-flush dan pembersihan lewat defer dilewati. log.Fatal memanggil os.Exit(1) dan efeknya sama. Simpan os.Exit di satu tempat, di akhir main, dan taruh program sesungguhnya di fungsi run yang mengembalikan error, seperti pada contoh subcommand:
func main() {
if err := run(os.Args[1:]); err != nil {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
}
}
Tulis pesan error ke os.Stderr, bukan os.Stdout, agar tetap terlihat saat output dialihkan ke file atau di-pipe ke perintah lain. Panic yang tidak di-recover akan keluar dengan status 2.
Kesalahan umum
- Mengakses indeks
os.Argstanpa memeriksa panjangnya. Argumen yang tidak ada membuat program panic. - Membaca flag sebelum
flag.Parse(). Kamu akan mendapat nilai default. - Lupa
*.fmt.Println(port)mencetak alamat seperti0xc000012345, bukan nilainya. - Menaruh flag setelah argumen posisional.
prog input.txt -vtidak mem-parse-v. -verbose falseuntuk flag bool. Tulis-verbose=false.- Memanggil
os.Exitataulog.Fataljauh di dalam program. Pembersihan yang ditunda tidak pernah berjalan dan kodenya tidak bisa diuji. Kembalikan error sampai kemain.
Pertanyaan yang sering diajukan
Bagaimana cara mengambil argumen command line di Go?
os.Args adalah []string yang berisi nama program di indeks 0 dan argumen-argumennya setelah itu. os.Args[1:] adalah argumen yang diketik pengguna. Periksa len(os.Args) sebelum mengakses indeksnya, atau program akan panic saat sebuah argumen tidak ada.
Bagaimana cara memakai package flag di Go?
Deklarasikan flag, panggil flag.Parse(), lalu baca nilainya: port := flag.Int("port", 8080, "port to listen on"), flag.Parse(), fmt.Println(*port). Fungsi-fungsinya mengembalikan pointer. Pengguna menulis -port=9000, -port 9000, atau --port 9000, dan -h mencetak teks bantuan yang dibuat otomatis.
Bagaimana cara membaca environment variable di Go?
os.Getenv("HOME") mengembalikan nilainya, atau string kosong kalau variabel itu tidak diset. Untuk membedakan antara tidak diset dan diset kosong, pakai v, ok := os.LookupEnv("HOME"). os.Setenv mengubah environment proses yang sedang berjalan dan proses anak yang dijalankannya sesudah itu.
Apakah os.Exit menjalankan fungsi yang ditunda (defer) di Go?
Tidak. os.Exit langsung mengakhiri proses dengan status code yang diberikan, dan panggilan defer tidak dijalankan, jadi output yang masih di buffer bisa hilang dan file bisa tidak di-flush. Pola yang umum adalah func main() { if err := run(); err != nil { fmt.Fprintln(os.Stderr, err); os.Exit(1) } }, dengan semua pekerjaan dan defer di dalam run.