Summary
In parseFlags (v3 main), the branch handling a lone - argument appends it to posArgs and then executes a plain break, which exits the entire rearrangement loop. Every remaining command-line argument after the - is dropped without error: myapp - foo bar ends up with cmd.Args() == ["-"].
Static-analysis finding based on reading main; not executed here.
Location
- File:
command_parse.go
- Function:
(*Command).parseFlags
- Relevant code:
numMinuses := 1
// this is same as firstArg == "-"
if len(firstArg) == 1 {
posArgs = append(posArgs, firstArg)
break
}
Problem
Compare this branch with every sibling path in the same loop:
- empty argument ?
append(posArgs, rargs[0]) + continue
"--" ? appends the arg (if completion mode) plus all of rargs[1:], then returns
- positional (
firstArg[0] != '-') ? append(posArgs, firstArg) + continue; if it names a subcommand, append(posArgs, rargs...) and return
- non-letter after
- (e.g. -3) ? append(posArgs, rargs...) + return
The lone - is the only hyphen-path that stops parsing without preserving the unconsumed remainder. Since the loop's post-statement only advances rargs between iterations, break here throws away rargs[1:] entirely.
Trigger / Reproduction
Based on source reading:
Iteration 1: firstArg == "-" ? len(firstArg) == 1 matches ? posArgs = ["-"] ? break.
Result: cmd.Args().Len() == 1, containing only -. foo and bar never reach the action.
Expected: the arguments are retained - either ["-", "foo", "bar"] (matching Go's stdlib flag, which treats a bare - like an ordinary operand) or at minimum everything from - onward, mirroring the -- and non-letter branches.
Expected Behavior
A single hyphen is conventionally used as an operand (stdin placeholder) or a terminator; in both interpretations the arguments that follow must survive into cmd.Args().
Actual Behavior
They are silently discarded; no error is returned.
Impact
Any CLI invocation that passes - (very common for "read stdin") followed by further operands loses those operands. Because nothing errors, callers observe truncated Args() with no diagnostic, which is difficult to debug downstream.
Suggested Direction
Mirror the neighboring branches: replace break with appending the rest of rargs and returning (terminator semantics), or continue after appending just firstArg (operand semantics). Either preserves user data; which one matches intent should be confirmed against the v2 behavior.
Evidence
- Loop structure at the top of
parseFlags shows no other mechanism that would revisit discarded args.
- All four alternative branches in the same function explicitly preserve the remainder, demonstrating that dropping it here is anomalous rather than intended.
Summary
In
parseFlags(v3main), the branch handling a lone-argument appends it toposArgsand then executes a plainbreak, which exits the entire rearrangement loop. Every remaining command-line argument after the-is dropped without error:myapp - foo barends up withcmd.Args()==["-"].Static-analysis finding based on reading
main; not executed here.Location
command_parse.go(*Command).parseFlagsProblem
Compare this branch with every sibling path in the same loop:
append(posArgs, rargs[0])+continue"--"? appends the arg (if completion mode) plus all ofrargs[1:], then returnsfirstArg[0] != '-') ?append(posArgs, firstArg)+continue; if it names a subcommand,append(posArgs, rargs...)and return-(e.g.-3) ?append(posArgs, rargs...)+ returnThe lone
-is the only hyphen-path that stops parsing without preserving the unconsumed remainder. Since the loop's post-statement only advancesrargsbetween iterations,breakhere throws awayrargs[1:]entirely.Trigger / Reproduction
Based on source reading:
$ myapp - foo barIteration 1:
firstArg == "-"?len(firstArg) == 1matches ?posArgs = ["-"]?break.Result:
cmd.Args().Len() == 1, containing only-.fooandbarnever reach the action.Expected: the arguments are retained - either
["-", "foo", "bar"](matching Go's stdlibflag, which treats a bare-like an ordinary operand) or at minimum everything from-onward, mirroring the--and non-letter branches.Expected Behavior
A single hyphen is conventionally used as an operand (stdin placeholder) or a terminator; in both interpretations the arguments that follow must survive into
cmd.Args().Actual Behavior
They are silently discarded; no error is returned.
Impact
Any CLI invocation that passes
-(very common for "read stdin") followed by further operands loses those operands. Because nothing errors, callers observe truncatedArgs()with no diagnostic, which is difficult to debug downstream.Suggested Direction
Mirror the neighboring branches: replace
breakwith appending the rest ofrargsand returning (terminator semantics), orcontinueafter appending justfirstArg(operand semantics). Either preserves user data; which one matches intent should be confirmed against the v2 behavior.Evidence
parseFlagsshows no other mechanism that would revisit discarded args.