Bygga CLI-appar i Go med Cobra & Viper
CLI-utveckling i Go med Cobra- och Viper-ramverken
Kommandoradsgränssnitt (CLI) applikationer är essentiella verktyg för utvecklare, systemadministratörer och DevOps-professionella. Två Go-bibliotek har blivit de faktiska standarderna för CLI-utveckling i Go: Cobra för kommandostruktur och Viper för konfigurationshantering.
Go har etablerat sig som ett utmärkt språk för att bygga CLI-verktyg tack vare dess prestanda, enkel distribution och plattformsoberoende stöd.

Varför välja Go för CLI-applikationer
Go erbjuder övertygande fördelar för CLI-utveckling:
- Enkel binär distribution: Inga runtimeberoenden eller pakethanterare krävs
- Snabb exekvering: Nativ kompilering ger utmärkt prestanda
- Plattformsoberoende stöd: Enkel kompilering för Linux, macOS, Windows och fler
- Starkt standardbibliotek: Rikt verktyg för fil-I/O, nätverk och textbehandling
- Konkurrensthantering: Inbyggda goroutines för parallella operationer
- Statisk typning: Upptäck fel vid kompileringstid
Populära CLI-verktyg byggda med Go inkluderar Docker, Kubernetes (kubectl), Hugo, Terraform och GitHub CLI. Om du är ny på Go eller behöver en snabb referens, kolla in vårt Go Cheat Sheet för grundläggande Go-syntax och mönster.
Introduktion till Cobra
Cobra är ett bibliotek som tillhandahåller ett enkelt gränssnitt för att skapa kraftfulla moderna CLI-applikationer. Skapat av Steve Francia (spf13), samma författare bakom Hugo och Viper, används Cobra i många av de mest populära Go-projekten.
Nyckelfunktioner i Cobra
Kommandostruktur: Cobra implementerar kommandomönstret, vilket tillåter dig att skapa applikationer med kommandon och underkommandon (som git commit eller docker run).
Flagghantering: Både lokala och bestående flaggor med automatisk parsning och typomvandling.
Automatisk hjälp: Genererar hjälptext och användningsinformation automatiskt.
Intelligenta förslag: Ger förslag när användare skriver fel (“Menade du ‘status’?”).
Skalskomplettering: Genererar kompletteringsskript för bash, zsh, fish och PowerShell.
Flexibel utskrift: Fungerar smidigt med anpassade formaterare och utskriftsstilar.
Introduktion till Viper
Viper är en komplett konfigurationslösning för Go-applikationer, designad för att fungera smidigt med Cobra. Den hanterar konfiguration från flera källor med en tydlig prioriteringsordning.
Nyckelfunktioner i Viper
Flera konfigurationskällor:
- Konfigurationsfiler (JSON, YAML, TOML, HCL, INI, envfile, Java properties)
- Miljövariabler
- Kommandoradsflaggor
- Fjärrkonfigurationssystem (etcd, Consul)
- Standardvärden
Konfigurationsprioritetsordning:
- Explicita anrop till Set
- Kommandoradsflaggor
- Miljövariabler
- Konfigurationsfil
- Nyckelvärdesförråd
- Standardvärden
Live-övervakning: Övervakar konfigurationsfiler och laddar om automatiskt när ändringar sker.
Typomvandling: Automatisk omvandling till olika Go-typer (sträng, int, bool, varaktighet, etc.).
Att börja: Installation
Först, initialisera en ny Go-modul och installera båda biblioteken:
go mod init myapp
go get -u github.com/spf13/cobra@latest
go get -u github.com/spf13/viper@latest
Valfritt, installera Cobra CLI-genereraren för ramverk:
go install github.com/spf13/cobra-cli@latest
Bygg din första CLI-applikation
Låt oss bygga ett praktiskt exempel: ett uppgiftshanteringsverktyg med konfigurationsstöd.
Projektstruktur
mytasks/
├── cmd/
│ ├── root.go
│ ├── add.go
│ ├── list.go
│ └── complete.go
├── config/
│ └── config.go
├── main.go
└── config.yaml
Huvudinloppspunkt
// main.go
package main
import "mytasks/cmd"
func main() {
cmd.Execute()
}
Rotkommando med Viper-integration
// cmd/root.go
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cfgFile string
var rootCmd = &cobra.Command{
Use: "mytasks",
Short: "Ett enkelt uppgiftshanteringsverktyg",
Long: `MyTasks är ett CLI-uppgiftshanterare som hjälper dig organisera
dina dagliga uppgifter med lätthet. Byggt med Cobra och Viper.`,
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "",
"konfigurationsfil (standard är $HOME/.mytasks.yaml)")
rootCmd.PersistentFlags().String("db",
"databashanteringsfilens plats")
viper.BindPFlag("database", rootCmd.PersistentFlags().Lookup("db"))
}
func initConfig() {
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
home, err := os.UserHomeDir()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
viper.AddConfigPath(home)
viper.AddConfigPath(".")
viper.SetConfigType("yaml")
viper.SetConfigName(".mytasks")
}
viper.SetEnvPrefix("MYTASKS")
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Använder konfigurationsfil:", viper.ConfigFileUsed())
}
}
Lägga till underkommandon
// cmd/add.go
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var priority string
var addCmd = &cobra.Command{
Use: "add [uppgiftsbeskrivning]",
Short: "Lägg till en ny uppgift",
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
task := args[0]
db := viper.GetString("database")
fmt.Printf("Lägger till uppgift: %s\n", task)
fmt.Printf("Prioritet: %s\n", priority)
fmt.Printf("Databas: %s\n", db)
// Här skulle du implementera faktisk uppgiftslagring
},
}
func init() {
rootCmd.AddCommand(addCmd)
addCmd.Flags().StringVarP(&priority, "priority", "p", "medium",
"Uppgiftsprioritet (låg, medium, hög)")
}
Lista-kommando
// cmd/list.go
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var showCompleted bool
var listCmd = &cobra.Command{
Use: "list",
Short: "Lista alla uppgifter",
Run: func(cmd *cobra.Command, args []string) {
db := viper.GetString("database")
fmt.Printf("Listar uppgifter från: %s\n", db)
fmt.Printf("Visa slutförda: %v\n", showCompleted)
// Här skulle du implementera faktisk uppgiftslistning
},
}
func init() {
rootCmd.AddCommand(listCmd)
listCmd.Flags().BoolVarP(&showCompleted, "completed", "c", false,
"Visa slutförda uppgifter")
}
Implementera datalagring
För en produktionsklar uppgiftshanterings-CLI behöver du implementera faktisk datalagring. Medan vi använder en enkel databasvägkonfiguration här, har du flera alternativ för att spara data:
- SQLite: Lättviktsdatabas utan server, perfekt för CLI-verktyg
- PostgreSQL/MySQL: Fullfjädrade databaser för mer komplexa applikationer
- JSON/YAML-filer: Enkel filbaserad lagring för lättviktsbehov
- Inbyggda databaser: BoltDB, BadgerDB för nyckelvärdeslagring
Om du arbetar med relationella databaser som PostgreSQL, vill du använda ett ORM eller frågebyggare. För en omfattande jämförelse av Go-databibliotek, se vårt guide på Jämförelse av Go ORMs för PostgreSQL: GORM vs Ent vs Bun vs sqlc.
Avancerad konfiguration med Viper
Exempel på konfigurationsfil
# .mytasks.yaml
database: ~/.mytasks.db
format: table
colors: true
notifications:
enabled: true
sound: true
priorities:
high: red
medium: yellow
low: green
Läsning av inbäddad konfiguration
func getNotificationSettings() {
enabled := viper.GetBool("notifications.enabled")
sound := viper.GetBool("notifications.sound")
fmt.Printf("Meddelanden aktiverade: %v\n", enabled)
fmt.Printf("Ljud aktiverat: %v\n", sound)
}
func getPriorityColors() map[string]string {
return viper.GetStringMapString("priorities")
}
Miljövariabler
Viper läser automatiskt miljövariabler med det konfigurerade prefixet:
export MYTASKS_DATABASE=/tmp/tasks.db
export MYTASKS_NOTIFICATIONS_ENABLED=false
mytasks list
Live-konfigurationsuppdatering
func watchConfig() {
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Konfigurationsfil ändrad:", e.Name)
// Ladda om konfigurationsberoende komponenter
})
}
Bäst praxis
1. Använd Cobra Generator för konsistens
cobra-cli init
cobra-cli add serve
cobra-cli add create
2. Organisera kommandon i separata filer
Håll varje kommando i sin egen fil under cmd/ katalogen för underhållbarhet.
3. Utnyttja bestående flaggor
Använd bestående flaggor för alternativ som gäller för alla underkommandon:
rootCmd.PersistentFlags().StringP("output", "o", "text",
"Utskriftsformat (text, json, yaml)")
4. Implementera korrekt felhantering
var rootCmd = &cobra.Command{
Use: "myapp",
Short: "Min applikation",
RunE: func(cmd *cobra.Command, args []string) error {
if err := doSomething(); err != nil {
return fmt.Errorf("misslyckades med att göra något: %w", err)
}
return nil
},
}
5. Ge meningsfull hjälptext
var cmd = &cobra.Command{
Use: "deploy [miljö]",
Short: "Distribuera applikation till specificerad miljö",
Long: `Distribuerar byggs och distribuerar din applikation till den
specificerade miljön. Stödda miljöer är:
- utveckling (dev)
- staging
- produktion (prod)`,
Example: ` myapp deploy staging
myapp deploy production --version=1.2.3`,
}
6. Ställ rimliga standardvärden
func init() {
viper.SetDefault("port", 8080)
viper.SetDefault("timeout", "30s")
viper.SetDefault("retries", 3)
}
7. Validera konfiguration
func validateConfig() error {
port := viper.GetInt("port")
if port < 1024 || port > 65535 {
return fmt.Errorf("ogiltig port: %d", port)
}
return nil
}
Testning av CLI-applikationer
Testning av kommandon
// cmd/root_test.go
package cmd
import (
"bytes"
"testing"
)
func TestRootCommand(t *testing.T) {
cmd := rootCmd
b := bytes.NewBufferString("")
cmd.SetOut(b)
cmd.SetArgs([]string{"--help"})
if err := cmd.Execute(); err != nil {
t.Fatalf("kommandoutförande misslyckades: %v", err)
}
}
Testning med olika konfigurationer
func TestWithConfig(t *testing.T) {
viper.Set("database", "/tmp/test.db")
viper.Set("debug", true)
// Kör dina tester
viper.Reset() // Rensa upp
}
Generera Shell-kompletteringar
Cobra kan generera kompletteringsskript för olika skal:
// cmd/completion.go
package cmd
import (
"os"
"github.com/spf13/cobra"
)
var completionCmd = &cobra.Command{
Use: "completion [bash|zsh|fish|powershell]",
Short: "Generera kompletteringsskript",
Long: `För att ladda kompletteringar:
Bash:
$ source <(mytasks completion bash)
Zsh:
$ source <(mytasks completion zsh)
Fish:
$ mytasks completion fish | source
PowerShell:
PS> mytasks completion powershell | Out-String | Invoke-Expression
`,
DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
Args: cobra.ExactValidArgs(1),
Run: func(cmd *cobra.Command, args []string) {
switch args[0] {
case "bash":
cmd.Root().GenBashCompletion(os.Stdout)
case "zsh":
cmd.Root().GenZshCompletion(os.Stdout)
case "fish":
cmd.Root().GenFishCompletion(os.Stdout, true)
case "powershell":
cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout)
}
},
}
func init() {
rootCmd.AddCommand(completionCmd)
}
Byggande och distribution
Bygg för flera plattformar
# Linux
GOOS=linux GOARCH=amd64 go build -o mytasks-linux-amd64
# macOS
GOOS=darwin GOARCH=amd64 go build -o mytasks-darwin-amd64
GOOS=darwin GOARCH=arm64 go build -o mytasks-darwin-arm64
# Windows
GOOS=windows GOARCH=amd64 go build -o mytasks-windows-amd64.exe
Minska binärstorlek
go build -ldflags="-s -w" -o mytasks
Lägg till versionsinformation
// cmd/version.go
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var (
Version = "dev"
Commit = "none"
BuildTime = "unknown"
)
var versionCmd = &cobra.Command{
Use: "version",
Short: "Skriv ut versionsinformation",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Version: %s\n", Version)
fmt.Printf("Commit: %s\n", Commit)
fmt.Printf("Byggd: %s\n", BuildTime)
},
}
func init() {
rootCmd.AddCommand(versionCmd)
}
Bygg med versionsinformation:
go build -ldflags="-X 'mytasks/cmd.Version=1.0.0' \
-X 'mytasks/cmd.Commit=$(git rev-parse HEAD)' \
-X 'mytasks/cmd.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)'" \
-o mytasks
Verkliga exempel
Populära öppna källkodsverktyg byggda med Cobra och Viper:
- kubectl: Kubernetes kommandoradsverktyg
- Hugo: Statisk webbplatsgenerator
- GitHub CLI (gh): GitHubs officiella CLI
- Docker CLI: Behållarhantering
- Helm: Kubernetes pakethanterare
- Skaffold: Kubernetes utvecklingsflödesverktyg
- Cobra CLI: Självhosting - Cobra använder sig själv!
Utöver traditionella DevOps-verktyg sträcker sig Gos CLI-möjligheter till AI och maskininlärningsapplikationer. Om du är intresserad av att bygga CLI-verktyg som interagerar med stora språkmodeller, kolla in vår guide om Begränsa LLMs med strukturerad output med hjälp av Ollama och Go, som visar hur man bygger Go-applikationer som arbetar med AI-modeller.
Användbara resurser
- Cobra GitHub Repository
- Viper GitHub Repository
- Cobra Användarhandbok
- Viper Dokumentation
- Bästa praxis för Go CLI-applikationer
Slutsats
Cobra och Viper tillsammans ger en kraftfull grund för att bygga professionella CLI-applikationer i Go. Cobra hanterar kommandostrukturen, flaggparsing och hjälpgenerering, medan Viper hanterar konfiguration från flera källor med intelligent prioritering.
Denna kombination gör att du kan skapa CLI-verktyg som är:
- Lätta att använda med intuitiva kommandon och automatisk hjälp
- Flexibla med flera konfigurationskällor
- Professionella med shell-kompletteringar och korrekt felhantering
- Underhållbara med ren kodorganisation
- Portabla över olika plattformar
Oavsett om du bygger utvecklarverktyg, systemverktyg eller DevOps-automatisering, ger Cobra och Viper den solida grund du behöver för att skapa CLI-applikationer som användare kommer att älska.