alecthomas / alecthomas/kingpin
Bare "-" argument is tokenized with an empty Value, so positional args receive "" instead of "-"
- Dominant language
- Go
- Stars
- 3.6k
- Forks
- 279
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
The tokenizer constructs the token for a bare `-` argument **without setting its `Value`**, so a lone dash on the command line reaches argument matching as an *empty string*. Applications consequently cannot receive `-` (the conventional "stdin" placeholder) as a positional argument value.
*This report is based on static analysis of master; I have not executed the code.*
## Location
- File: `parser.go`
- Function: `(*ParseContext).Next`, short-argument branch
```go
if strings.HasPrefix(arg, "-") {
if len(arg) == 1 {
return &Token{Index: p.argi, Type: TokenArg} // Value field omitted -> ""
}
...
}
```
and the consumption site in `parse`:
```go
case TokenArg:
...
context.matchedArg(arg, token.String())
```
where `(*Token).String()` for `TokenArg` returns `t.Value` — i.e. `""`.
## Problem
For input `-`, the tokenizer recognizes it as a non-flag argument but drops the actual character when building the token (`Token{Index: ..., Type: TokenArg}` has zero-valued `Value`). Every downstream consumer that uses `token.String()` as the argument value therefore sees an empty string instead of `"-"`.
Concretely, for:
```go
input := kingpin.Arg("input", "input file ('-' for stdin)").String()
kingpin.Parse()
```
running `myapp -` sets `*input` to `""`, not `"-"`.
Note the contrast with the surrounding code: every other path (`TokenLong`, combined short flags, `@file` expansion errors, plain arguments) explicitly propagates the value into the token.
## Trigger / Reproduction
Any application declaring a positional argument, invoked with a single `-` argument:
```sh
myapp -
```
(Static-analysis finding — derived from the token construction and `String()` implementations quoted above.)
## Expected Behavior
A bare `-` is treated as a regular argument whose value is `-` (this is the widespread POSIX convention for "read stdin"), i.e. the token should be `&Token{Index: p.argi, Type: TokenArg, Value: arg}`.
## Actual Behavior
The positional argument receives `""`.
## Impact
Apps built with kingpin cannot implement the standard `-`/stdin convention through declared args; the value is silently emptied rather than producing an error, so e.g. an `ExistingFile()`-validated arg reports the confusing error for `""` instead of `-`. Workarounds require pre-scanning `os.Args`.
## Suggested Direction
Populate the value: `return &Token{Index: p.argi, Type: TokenArg, Value: arg}`. If treating `-` as a flag-like special case was intentional, it should at minimum be documented; nothing in the docs mentions it.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.