Program baris perintah (command line) menerima argumen dari terminal, dan Go menyediakan paket flag di pustaka standar untuk mengurainya menjadi opsi bernama. Topik ini membahas cara mendeklarasikan opsi dengan nilai default, menyusun subperintah melalui flag.NewFlagSet, serta membandingkannya dengan cobra, yaitu pustaka eksternal dari spf13 yang dipakai untuk program CLI bertingkat. Contohnya berupa dua alat kecil, yaitu alat salam dan alat catatan, yang dijalankan tanpa argumen maupun dengan argumen eksplisit sehingga perilakunya terlihat lengkap. Setelah membacanya, antarmuka baris perintah dapat dibangun dengan parsing argumen yang benar dan pesan pemakaian yang informatif.
Parsing argumen dengan paket flag#
Paket flag mendeklarasikan opsi melalui fungsi seperti flag.String dan flag.Int, dan masing-masing mengembalikan pointer ke variabel yang akan diisi. Urutan panggilannya adalah mendeklarasikan seluruh opsi, memanggil flag.Parse untuk mengurai os.Args, kemudian membaca nilai melalui pointer tersebut. Setiap opsi memiliki nilai default, sehingga program tetap dapat dijalankan ketika opsi itu tidak diberikan, dan paket ini otomatis menyediakan opsi -h yang mencetak daftar opsi beserta teks penjelasannya. Program berikut membentuk alat salam dengan dua opsi dan mencetak hasilnya menggunakan nilai default.
package main
import (
"flag"
"fmt"
"strings"
)
func main() {
nama := flag.String("nama", "Dunia", "nama penerima salam")
ulang := flag.Int("ulang", 1, "banyaknya pengulangan")
flag.Parse()
fmt.Print(strings.Repeat(fmt.Sprintf("Halo, %s!\n", *nama), *ulang))
}Halo, Dunia!Keluaran di atas berasal dari eksekusi tanpa argumen, sehingga kedua opsi memakai nilai default Dunia dan 1. Pointer nama dan ulang diisi oleh flag.Parse berdasarkan argumen baris perintah, dan strings.Repeat mengulang salam sesuai nilai ulang. Urutan opsi pada baris perintah bebas karena flag.Parse mencocokkan namanya dan bukan posisinya, sedangkan teks penjelasan pada setiap deklarasi menjadi isi halaman bantuan opsi -h. Pemanggilan dengan argumen eksplisit mengubah kedua nilai tersebut tanpa perubahan apa pun pada kode, sebagaimana diperlihatkan blok terminal pada bagian berikutnya.
Subperintah dengan FlagSet#
Program CLI sering memakai subperintah (subcommand), yaitu kata pertama yang menentukan perilaku program, seperti go mod init yang memilih subperintah mod lalu init. Paket flag mendukung pola ini melalui flag.NewFlagSet, yaitu kumpulan opsi mandiri yang diparsing dari potongan os.Args milik subperintahnya. Argumen posisi, yakni argumen yang tidak diawali tanda hubung, tetap dapat dibaca melalui metode Args milik FlagSet tersebut. Program berikut membentuk alat catatan dengan dua subperintah, yaitu salam dengan opsi dan tambah dengan argumen posisi berupa bilangan.
package main
import (
"flag"
"fmt"
"os"
"strconv"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("pemakaian: catat <subperintah> [opsi]")
fmt.Println("subperintah: salam, tambah")
return
}
switch os.Args[1] {
case "salam":
fs := flag.NewFlagSet("salam", flag.ExitOnError)
nama := fs.String("nama", "Dunia", "nama penerima salam")
fs.Parse(os.Args[2:])
fmt.Printf("Halo, %s!\n", *nama)
case "tambah":
fs := flag.NewFlagSet("tambah", flag.ExitOnError)
fs.Parse(os.Args[2:])
total := 0
for _, argumen := range fs.Args() {
n, err := strconv.Atoi(argumen)
if err != nil {
fmt.Println("bukan bilangan bulat:", argumen)
os.Exit(1)
}
total += n
}
fmt.Println("jumlah:", total)
default:
fmt.Println("subperintah tidak dikenal:", os.Args[1])
os.Exit(1)
}
}pemakaian: catat <subperintah> [opsi]
subperintah: salam, tambahKeluaran di atas berasal dari eksekusi tanpa argumen, sehingga program mencetak petunjuk pemakaiannya dan berhenti dengan status nol. Struktur switch pada os.Args[1] memilih subperintahnya, dan setiap cabang membuat FlagSet sendiri supaya opsi antarsubperintah tidak saling bercampur. Subperintah tambah mengurai argumen posisinya satu per satu dengan strconv.Atoi, sehingga argumen yang bukan bilangan menghentikan program dengan status keluar 1. Kedua alat dijalankan dari terminal dengan argumen eksplisit sebagaimana berikut.
# siapkan folder kerja untuk topik ini
mkdir -p /tmp/gopustaka/flag
cp alat-salam.go alat-catatan.go /tmp/gopustaka/flag/
cd /tmp/gopustaka/flag
# jalankan alat salam dengan kedua opsinya
go run alat-salam.go -nama=Ali -ulang=2
# jalankan subperintah salam dengan opsinya
go run alat-catatan.go salam -nama=Budi
# jalankan subperintah tambah dengan argumen posisi
go run alat-catatan.go tambah 2 3 5Halo, Ali!
Halo, Ali!
Halo, Budi!
jumlah: 10cobra untuk CLI bertingkat#
Paket cobra dari github.com/spf13/cobra adalah pustaka eksternal yang menyusun program CLI di atas pohon perintah, yaitu perintah utama beserta subperintah yang dapat bersarang beberapa tingkat. Setiap perintah dideklarasikan sebagai struct cobra.Command yang memuat nama, teks penjelasan singkat, daftar subperintahnya, dan fungsi yang dijalankan ketika perintah tersebut dipilih. Paket ini juga menghasilkan halaman bantuan otomatis untuk setiap tingkat perintah dan menambahkan pelengkapan tab (shell completion) untuk shell bash, zsh, serta fish. Contoh berikut memperlihatkan bentuk deklarasinya yang tidak dijalankan karena pustakanya berada di luar pustaka standar.
// tidak-dijalankan
var salamCmd = &cobra.Command{
Use: "salam",
Short: "Mencetak salam untuk satu nama",
RunE: func(cmd *cobra.Command, args []string) error {
nama, _ := cmd.Flags().GetString("nama")
fmt.Printf("Halo, %s!\n", nama)
return nil
},
}
func init() {
salamCmd.Flags().String("nama", "Dunia", "nama penerima salam")
rootCmd.AddCommand(salamCmd)
}Fragmen di atas memperlihatkan perbedaan pendekatannya terhadap paket flag. Field Use menentukan nama subperintah pada baris perintah, field Short menjadi teks pada halaman bantuan, dan RunE menampung logikanya beserta error yang dapat dikembalikan. Pendaftaran opsi tetap menyerupai flag.String, karena cobra membangun penanganan opsinya di atas pustaka pflag, yaitu pustaka terpisah yang tata polanya mengikuti paket flag. Sebagai perbandingan, alat salam dua opsi pada bagian awal topik ini cukup ditulis dengan flag saja, sedangkan cobra memberi keuntungan ketika jumlah subperintah dan tingkat sarangnya bertambah.
Kesalahan umum#
- Lupa memanggil
flag.Parse. Deklarasi opsi hanya mendaftarkannya, sehingga tanpaParseseluruh pointer tetap berisi nilai default dan argumen baris perintah diabaikan. Perbaikannya, panggilflag.Parseataufs.Parsetepat setelah seluruh opsi dideklarasikan. - Membaca argumen posisi dari
flag.Argspadahal memakai FlagSet sendiri. Fungsi globalflag.Argsmengembalikan argumen milikCommandLine, bukan milik FlagSet subperintah, sehingga hasilnya selalu kosong. Perbaikannya, gunakan metodeArgspada FlagSet yang diparsing. - Mencampur opsi dua FlagSet dalam satu pemanggilan. FlagSet bersifat mandiri, sehingga opsi yang dideklarasikan pada subperintah lain tidak dikenal dan parsingnya gagal. Perbaikannya, deklarasikan ulang opsi yang dibutuhkan pada setiap FlagSet.
- Mengasumsikan argumen posisi berada sebelum opsi. Paket
flagmenghentikan parsing pada argumen posisi pertama, sehingga opsi setelahnya masuk keArgs. Perbaikannya, tempatkan opsi sebelum argumen posisi atau terima urutan itu sebagai konvensi programnya. - Menghentikan program dari dalam subperintah tanpa status keluar.
returnbiasa melaporkan keberhasilan meskipun pekerjaannya gagal, sehingga skrip pemanggil tidak mengetahuinya. Perbaikannya, panggilos.Exit(1)atau kembalikan error sesuai pola programnya.
Ringkasan#
- Paket
flagmendeklarasikan opsi melaluiflag.Stringdanflag.Intyang mengembalikan pointer, kemudian mengurainya denganflag.Parse. - Nilai default membuat program tetap dapat dijalankan tanpa argumen, dan opsi
-htersedia secara otomatis beserta teks penjelasannya. flag.NewFlagSetmembangun subperintah dengan kumpulan opsi mandiri, sedangkan argumen posisinya dibaca melalui metodeArgs.- cobra adalah pustaka eksternal untuk CLI bertingkat dengan pohon perintah, bantuan otomatis, dan pelengkapan tab, sedangkan
flagcukup untuk alat yang sederhana.
Referensi#
- Package flag — The Go Authors — Dokumentasi resmi parsing argumen baris perintah beserta FlagSet dan status keluarnya.
- spf13/cobra — GitHub — Halaman resmi pustaka cobra beserta contoh deklarasi perintah dan subperintahnya.
- The Go Documentation — Halaman induk dokumentasi resmi Go yang memuat panduan pustaka standar.