Search code examples
goflag-go

How to provide the command line args first and then the flags in golang?


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 :

Solution

  • 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)
    }