package main import ( "errors" "fmt" "os" "strconv" "strings" ) type Options struct { Verbose bool Output string Count int Args []string } // Parse accepts long options, short options, and "--" as an option terminator. func Parse(args []string) (Options, error) { opts := Options{Count: 1} for i := 0; i < len(args); i++ { arg := args[i] if arg == "--" { opts.Args = append(opts.Args, args[i+1:]...) break } switch { case arg == "-v" || arg == "--verbose": opts.Verbose = true case arg == "-o" || arg == "--output": i++ if i >= len(args) { return Options{}, fmt.Errorf("%s requires a value", arg) } opts.Output = args[i] case strings.HasPrefix(arg, "--output="): opts.Output = strings.TrimPrefix(arg, "--output=") if opts.Output == "" { return Options{}, errors.New("--output requires a value") } case arg == "-n" || arg == "--count": i++ if i >= len(args) { return Options{}, fmt.Errorf("%s requires a value", arg) } count, err := parseCount(args[i]) if err != nil { return Options{}, err } opts.Count = count case strings.HasPrefix(arg, "--count="): count, err := parseCount(strings.TrimPrefix(arg, "--count=")) if err != nil { return Options{}, err } opts.Count = count case strings.HasPrefix(arg, "-"): return Options{}, fmt.Errorf("unknown option %q", arg) default: opts.Args = append(opts.Args, arg) } } return opts, nil } func parseCount(value string) (int, error) { count, err := strconv.Atoi(value) if err != nil || count < 1 { return 0, fmt.Errorf("count must be a positive integer, got %q", value) } return count, nil } func usage() { fmt.Fprintf(os.Stderr, `Usage: %s [options] [arguments...] Options: -v, --verbose Enable verbose output -o, --output FILE Write output to FILE -n, --count N Repeat N times (default 1) -h, --help Show this help `, os.Args[0]) } func main() { for _, arg := range os.Args[1:] { if arg == "-h" || arg == "--help" { usage() return } } opts, err := Parse(os.Args[1:]) if err != nil { fmt.Fprintln(os.Stderr, "error:", err) usage() os.Exit(2) } if opts.Verbose { fmt.Fprintf(os.Stderr, "output=%q count=%d args=%q\n", opts.Output, opts.Count, opts.Args) } text := strings.Join(opts.Args, " ") var output strings.Builder for i := 0; i < opts.Count; i++ { output.WriteString(text) output.WriteByte('\n') } if opts.Output == "" { fmt.Print(output.String()) return } if err := os.WriteFile(opts.Output, []byte(output.String()), 0o644); err != nil { fmt.Fprintln(os.Stderr, "error:", err) os.Exit(1) } }