본문 바로가기

프로그래밍/golang

[Golang] flag로 서브커맨드 만들기

 

Go언어로 CLI 도구를 개발할 때, git이나 docker처럼 하나의 실행 파일에서 여러 기능을 수행하는 서브커맨드 구조가 자주 사용이 됩니다.

외부 라이브러리 없이 표준 라이브러리인 'flag' 패키지의 'FlagSet'을 활용해 구현하는 방법을 알아봅시다.

 

1. flag.NewFlagSet

표준 flag 패키지는 기본적으로 전역 플래그를 관리하는데,

서브커맨드 구조에서는 커맨드마다 서로 다른 플래그를 가져야 함으로,

flag.NewFlagSet을 사용해 독립적인 플래그 집합을 생성해야 합니다. 

 

 

예시) 

go run main.go serve -port=8080 -env=prod

 

os.Args[0] main.go 실행 파일 경로
os.Args[1] serve 서브커맨드 이름
os.Args[2] -port=8080 -env=prod 플래그 데이터
형태 : mycli <command> [command flags] [args] 

 

 

2. 예제 코드

package main

import (
	"flag"
	"fmt"
	"os"
)

func main() {
	if len(os.Args) < 2 {
		printTopUsage()
		os.Exit(2)
	}

	switch os.Args[1] {
	case "serve":
		runServe(os.Args[2:])
	case "migrate":
		runMigrate(os.Args[2:])
	case "-h", "--help", "help":
		printTopUsage()
	default:
		fmt.Fprintf(os.Stderr, "unknown command: %s\n\n", os.Args[1])
		printTopUsage()
		os.Exit(2)
	}
}

// serve 커맨드
func runServe(args []string) {
	fs := flag.NewFlagSet("serve", flag.ContinueOnError)
	fs.SetOutput(os.Stderr)

	port := fs.Int("port", 8080, "listen port")
	env := fs.String("env", "dev", "environment name")
	
    // 서브 커맨드 파싱
	if err := fs.Parse(args); err != nil {
		os.Exit(2)
	}

	// 정의 안된 추가 인자가 있을 시 종료
	if extra := fs.Args(); len(extra) > 0 {
		fmt.Fprintf(os.Stderr, "unexpected args: %v\n\n", extra)
		fs.Usage()
		os.Exit(2)
	}

	fmt.Printf("serve: env=%s port=%d\n", *env, *port)
}

// migrate 커맨드
func runMigrate(args []string) {
	fs := flag.NewFlagSet("migrate", flag.ContinueOnError)
	fs.SetOutput(os.Stderr)

	dryRun := fs.Bool("dry-run", false, "print actions only")
	steps := fs.Int("steps", 0, "limit number of steps, 0 means all")

	if err := fs.Parse(args); err != nil {
		os.Exit(2)
	}

	fmt.Printf("migrate: dry_run=%v steps=%d\n", *dryRun, *steps)
	if remaining := fs.Args(); len(remaining) > 0 {
		fmt.Printf("migrate args: %v\n", remaining)
	}
}

func printTopUsage() {
	fmt.Fprintln(os.Stderr, "usage:")
	fmt.Fprintln(os.Stderr, "  mycli <command> [flags]")
	fmt.Fprintln(os.Stderr)
	fmt.Fprintln(os.Stderr, "commands:")
	fmt.Fprintln(os.Stderr, "  serve    run server")
	fmt.Fprintln(os.Stderr, "  migrate  run migrations")
	fmt.Fprintln(os.Stderr)
	fmt.Fprintln(os.Stderr, "examples:")
	fmt.Fprintln(os.Stderr, "  go run ./flag/advanced/subcommands serve -port=8080")
	fmt.Fprintln(os.Stderr, "  go run ./flag/advanced/subcommands migrate -dry-run")
}

 

'프로그래밍 > golang' 카테고리의 다른 글

[Golang] Rate Limit 패턴  (0) 2026.03.21
[Go] 고루틴 워커 풀(Worker Pool)  (0) 2026.03.21
[Golang] Context란?  (0) 2026.03.21
[Golang] 채널(Channel)이란?  (0) 2026.03.18
[Golang] errgroup 이란?  (0) 2026.03.18