Skip to content

Commit e976e98

Browse files
committed
Add a new function to parse a line containing environment variables
1 parent 2c8720d commit e976e98

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ args, err := shellwords.Parse("./foo --bar=baz")
1313
// args should be ["./foo", "--bar=baz"]
1414
```
1515

16+
```go
17+
envs, args, err := shellwords.ParseWithEnvs("FOO=foo BAR=baz ./foo --bar=baz")
18+
// envs should be ["FOO=foo", "BAR=baz"]
19+
// args should be ["./foo", "--bar=baz"]
20+
```
21+
1622
```go
1723
os.Setenv("FOO", "bar")
1824
p := shellwords.NewParser()

shellwords.go

+29
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,35 @@ loop:
290290
return args, nil
291291
}
292292

293+
func (p *Parser) ParseWithEnvs(line string) (envs []string, args []string, err error) {
294+
_args, err := p.Parse(line)
295+
if err != nil {
296+
return nil, nil, err
297+
}
298+
envs = []string{}
299+
args = []string{}
300+
parsingEnv := true
301+
for _, arg := range _args {
302+
if parsingEnv && isEnv(arg) {
303+
envs = append(envs, arg)
304+
} else {
305+
if parsingEnv {
306+
parsingEnv = false
307+
}
308+
args = append(args, arg)
309+
}
310+
}
311+
return envs, args, nil
312+
}
313+
314+
func isEnv(arg string) bool {
315+
return len(strings.Split(arg, "=")) == 2
316+
}
317+
293318
func Parse(line string) ([]string, error) {
294319
return NewParser().Parse(line)
295320
}
321+
322+
func ParseWithEnvs(line string) (envs []string, args []string, err error) {
323+
return NewParser().ParseWithEnvs(line)
324+
}

shellwords_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -407,3 +407,45 @@ func TestEnvInQuoted(t *testing.T) {
407407
t.Fatalf("Expected %#v, but %#v:", expected, args)
408408
}
409409
}
410+
411+
func TestParseWithEnvs(t *testing.T) {
412+
tests := []struct {
413+
line string
414+
wantEnvs, wantArgs []string
415+
}{
416+
{
417+
line: "FOO=foo cmd --args=A=B",
418+
wantEnvs: []string{"FOO=foo"},
419+
wantArgs: []string{"cmd", "--args=A=B"},
420+
},
421+
{
422+
line: "FOO=foo BAR=bar cmd --args=A=B -A=B",
423+
wantEnvs: []string{"FOO=foo", "BAR=bar"},
424+
wantArgs: []string{"cmd", "--args=A=B", "-A=B"},
425+
},
426+
{
427+
line: `sh -c "FOO=foo BAR=bar cmd --args=A=B -A=B"`,
428+
wantEnvs: []string{},
429+
wantArgs: []string{"sh", "-c", "FOO=foo BAR=bar cmd --args=A=B -A=B"},
430+
},
431+
{
432+
line: "cmd --args=A=B -A=B",
433+
wantEnvs: []string{},
434+
wantArgs: []string{"cmd", "--args=A=B", "-A=B"},
435+
},
436+
}
437+
for _, tt := range tests {
438+
t.Run(tt.line, func(t *testing.T) {
439+
envs, args, err := ParseWithEnvs(tt.line)
440+
if err != nil {
441+
t.Fatal(err)
442+
}
443+
if !reflect.DeepEqual(envs, tt.wantEnvs) {
444+
t.Errorf("Expected %#v, but %#v", tt.wantEnvs, envs)
445+
}
446+
if !reflect.DeepEqual(args, tt.wantArgs) {
447+
t.Errorf("Expected %#v, but %#v", tt.wantArgs, args)
448+
}
449+
})
450+
}
451+
}

0 commit comments

Comments
 (0)