숏컷 코드
mytool serve -port 8080 -debug
mytool migrate -dry-runserveCmd := flag.NewFlagSet("serve", flag.ContinueOnError)
port := serveCmd.Int("port", 8080, "server port")
debug := serveCmd.Bool("debug", false, "enable debug logs")
if err := serveCmd.Parse(os.Args[2:]); err != nil {
return err
}표준 flag 패키지는 작은 CLI에 충분하고, subcommand는 FlagSet을 나눠서 구성합니다.
문법
기본 flag는 이름, 기본값, 설명으로 만든다
name := flag.String("name", "guest", "user name")
count := flag.Int("count", 1, "repeat count")
verbose := flag.Bool("verbose", false, "verbose output")
flag.Parse()flag.String, flag.Int, flag.Bool은 값 포인터를 돌려줍니다.
fmt.Println(*name, *count, *verbose)남은 인자는 Args로 읽는다
flag.Parse()
args := flag.Args()옵션이 아닌 위치 인자는 Args()로 읽습니다. 파일 경로나 대상 이름처럼 순서가 있는 입력을 받을 때 사용합니다.
subcommand는 FlagSet을 분리한다
switch os.Args[1] {
case "serve":
serveCmd.Parse(os.Args[2:])
case "migrate":
migrateCmd.Parse(os.Args[2:])
default:
return fmt.Errorf("unknown command: %s", os.Args[1])
}표준 flag 패키지가 subcommand를 자동으로 관리해 주지는 않습니다. 명령별 FlagSet을 만들고 os.Args를 기준으로 직접 분기합니다.
선택 기준
| 상황 | 먼저 떠올릴 선택 |
|---|---|
| 작은 CLI 옵션 | 표준 flag |
| 명령 하나 | package-level flag 함수 |
| 여러 subcommand | 명령별 FlagSet |
| 위치 인자 | Args() |
| 복잡한 help/명령 트리 | CLI 프레임워크 검토 |
표준 flag는 단순하고 의존성이 없습니다. 반대로 중첩 subcommand, 자동 help, shell completion, config 파일 통합이 중요하면 별도 CLI 프레임워크가 더 나을 수 있습니다.
주의할 점
package-level flag는 전역 상태를 사용하므로 테스트나 여러 명령 조합에서 꼬이기 쉽습니다. 재사용 가능한 CLI 코드는 flag.NewFlagSet으로 명령 경계를 명시하는 편이 안전합니다. 또한 os.Args[1]를 읽기 전에는 인자 길이를 먼저 확인해야 panic을 피할 수 있습니다.
참고 링크
2 sources