Golang的Flag被解释为第一个os.Args参数。

huangapple go评论109阅读模式
英文:

Golang Flag gets interpreted as first os.Args argument

问题

我想这样运行我的程序:

go run launch.go http://example.com --m=2 --strat=par

"http://example.com" 被解释为第一个命令行参数,这是可以的,但是标志没有被解析,仍然保持默认值。如果我这样写:

go run launch.go --m=2 --strat=par http://example.com

那么"--m=2" 被解释为第一个参数(应该是URL)。

我也可以完全删除 os.Args,但是这样我只会有可选标志,而我想要一个(URL)是必需的。

这是我的代码:

package main

import (
    "fmt"
    "webcrawler/crawler"
    "webcrawler/model"
    "webcrawler/urlutils"
    "os"
    "flag"
)

func main() {
    if len(os.Args) < 2 {
        log.Fatal("Url must be provided as first argument")
    }

    strategy := flag.String("strat", "par", "par for parallel OR seq for sequential crawling strategy")
    routineMultiplier := flag.Int("m", 1, "Goroutine multiplier. Default 1x logical CPUs. Only works in parallel strategy")

    page := model.NewBasePage(os.Args[1])
    urlutils.BASE_URL = os.Args[1]
    flag.Parse()
    pages := crawler.Crawl(&page, *strategy, *routineMultiplier)
    fmt.Printf("Crawled: %d\n", len(pages))
}

我很确定这应该是可能的,但是我无法弄清楚如何做到。

编辑:
感谢 justinas 提供 flag.Args() 的提示。我现在将其调整为以下方式,它可以工作:

...
flag.Parse()

args := flag.Args()
if len(args) != 1 {
    log.Fatal("Only one argument (URL) allowed.")
}

page := model.NewBasePage(args[0])
...
英文:

I would like to run my program like this:

go run launch.go http://example.com --m=2 --strat=par

"http://example.com" gets interpreted as the first command line argument, which is ok, but the flags are not parsed after that and stay at the default value. If I put it like this:

go run launch.go --m=2 --strat=par http://example.com

then "--m=2" is interpreted as the first argument (which should be the URL).

I could also just remove the os.Args completely, but then I would have only optional flags and I want one (the URL) to be mandatory.

Here's my code:

package main

import (
	&quot;fmt&quot;
	&quot;webcrawler/crawler&quot;
	&quot;webcrawler/model&quot;
	&quot;webcrawler/urlutils&quot;
	&quot;os&quot;
	&quot;flag&quot;
)

func main() {
	if len(os.Args) &lt; 2 {
		log.Fatal(&quot;Url must be provided as first argument&quot;)
	}

	strategy := flag.String(&quot;strat&quot;, &quot;par&quot;, &quot;par for parallel OR seq for sequential crawling strategy&quot;)
	routineMultiplier := flag.Int(&quot;m&quot;, 1, &quot;Goroutine multiplier. Default 1x logical CPUs. Only works in parallel strategy&quot;)

	page := model.NewBasePage(os.Args[1])
	urlutils.BASE_URL = os.Args[1]
	flag.Parse()
	pages := crawler.Crawl(&amp;page, *strategy, *routineMultiplier)
	fmt.Printf(&quot;Crawled: %d\n&quot;, len(pages))
}

I am pretty sure that this should be possible, but I can't figure out how.

EDIT:
Thanks justinas for the hint with the flag.Args(). I now adapted it like this and it works:

...
flag.Parse()

args := flag.Args()
    if len(args) != 1 {
        log.Fatal(&quot;Only one argument (URL) allowed.&quot;)
    }

page := model.NewBasePage(args[0])
...

答案1

得分: 28

os.Args并不真正了解flag包,并包含所有命令行参数。请尝试使用flag.Args()(当然,在调用flag.Parse()之后)。

英文:

os.Args doesn't really know anything about the flag package and contains all command-line arguments. Try flag.Args() (after calling flag.Parse(), of course).

答案2

得分: 17

作为后续操作,要解析跟随命令的标志,例如:

runme init -m thisis

您可以创建自己的 flagset 来跳过第一个值,如下所示:

var myValue string
mySet := flag.NewFlagSet("", flag.ExitOnError)
mySet.StringVar(&myValue, "m", "mmmmm", "something")
mySet.Parse(os.Args[2:])
英文:

As a followup, to parse flags that follow a command like

runme init -m thisis

You can create your own flagset to skip the first value like

var myValue string
mySet := flag.NewFlagSet(&quot;&quot;,flag.ExitOnError)
mySet.StringVar(&amp;myValue,&quot;m&quot;,&quot;mmmmm&quot;,&quot;something&quot;)
mySet.Parse(os.Args[2:])

答案3

得分: 4

这个问题也困扰了我,因为我在我的应用程序中的几个地方调用了flag.String/flag.Int64等函数,我不想在各个地方都传递一个新的flag.FlagSet

// 如果一个命令行应用程序的使用方式是这样的:./app subcommand -flag -flag2
// flag.Parsesubcommand之后不会解析任何内容。
// 为了仍然能够使用flag.String/flag.Int64等函数而不创建一个新的flag.FlagSet,我们需要这个技巧来找到第一个带有破折号的参数,
// 这样我们就知道何时开始解析。
firstArgWithDash := 1
for i := 1; i < len(os.Args); i++ {
firstArgWithDash = i

if len(os.Args[i]) > 0 && os.Args[i][0] == '-' {
    break
}

}

flag.CommandLine.Parse(os.Args[firstArgWithDash:])

我之所以选择这种方式,是因为flag.Parse在内部实际上只是调用了flag.CommandLine.Parse(os.Args[1:])

英文:

This tripped me up too, and since I call flag.String/flag.Int64/etc in a couple of places in my app, I didn't want to have to pass around a new flag.FlagSet all over the place.

// If a commandline app works like this: ./app subcommand -flag -flag2
// `flag.Parse` won&#39;t parse anything after `subcommand`.
// To still be able to use `flag.String/flag.Int64` etc without creating
// a new `flag.FlagSet`, we need this hack to find the first arg that has a dash
// so we know when to start parsing
firstArgWithDash := 1
for i := 1; i &lt; len(os.Args); i++ {
	firstArgWithDash = i

	if len(os.Args[i]) &gt; 0 &amp;&amp; os.Args[i][0] == &#39;-&#39; {
		break
	}
}

flag.CommandLine.Parse(os.Args[firstArgWithDash:])

The reason I went with this is because flag.Parse just calls flag.CommandLine.Parse(os.Args[1:]) under the hood anyway.

答案4

得分: 0

你可以检查参数是否以"--"或"-"开头,并避免在循环中使用该参数。

例如:

for _, file := range os.Args[1:] {
	if strings.HasPrefix(file, "--") {
		continue
	}
    //执行操作
    }
英文:

You can check if the Arg starts with "--" or "-" and avoid using that Arg in a loop.

For example:

for _, file := range os.Args[1:] {
	if strings.HasPrefix(file, &quot;--&quot;) {
		continue
	}
    //do stuff
    }

huangapple
  • 本文由 发表于 2013年10月27日 18:51:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/19617229.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定