5

Golang's flag package reads the command line flags and args properly if the input provided is of the form : go run main.go -o filename.txt arg1 arg2

But if I try to provide the input like : go run main.go arg1 arg2 -o filename.txt, everything after main.go is read as arguments.

How to make this style work?

My program:

package main

import (
    "flag"
    "fmt"
)

func main() {

    var output string
    flag.StringVar(&output, "o", "", "Writes output to the file specified")
    flag.Parse()
    fmt.Println("Positional Args : ", flag.Args())
    fmt.Println("Flag -o : ", output)
}

go run main.go -o filename.txt arg1 arg2

Output:

Positional Args :  [arg1 arg2]
Flag -o :  filename.txt

go run main.go arg1 arg2 -o filename.txt

Output:

Positional Args :  [arg1 arg2 -o filename.txt]
Flag -o :
Mohit
  • 75
  • 1
  • 6
  • 1
    As it is documented in the package (https://pkg.go.dev/flag), "Flag parsing stops just before the first non-flag argument". – sigkilled Nov 27 '21 at 10:40
  • 1
    You can't do it with the standard package. Write it yourself or use one of the numerous third-party packages. – Peter Nov 27 '21 at 10:44
  • Some of your arguments are getting picked up by `go run`. Use `go build` and you won't be conflating `go run` arguments with your application's arguments – erik258 Nov 27 '21 at 16:12

1 Answers1

3

If you shimmy around with the contents of os.Args, it is possible to accept arg1 arg2 -o filename.txt

Go through the os.Args that is passed in from the command line in the for loop

If a - is seen then set a condition that indicates the first flag has been seen

If the condition is set then populate the "notargs" list. Otherwise, populate the "args" list

There is a bit of extra complication here as the args list that is used to set os.Args to the values that will do the flag processing must include the program name (the original os.Arg[0]) as the first value

This solution does not work with -o filename.txt arg1 arg2

package main

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

func main() {

    var output string
    var args[]string
    var notargs[]string
    var in_flags bool=false
    for i:=0; i<len(os.Args); i++ {
      if os.Args[i][0]=='-' {
       in_flags=true
      }
      if i==0 || in_flags {
        notargs=append(notargs,os.Args[i])
      } else {
        args=append(args,os.Args[i])
      }
    }
    os.Args=notargs
    flag.StringVar(&output, "o", "", "Writes output to the file specified")
    flag.Parse()
    fmt.Println("args ",args)
    fmt.Println("Flag -o : ", output)
}
Vorsprung
  • 32,923
  • 5
  • 39
  • 63