Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions shlex.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ func (t *tokenizer) scanStream() (*Token, error) {
switch nextRuneType {
case eofRuneClass:
switch {
case t.index == 0: // tonkenizer contains an empty string
case t.index == 0: // tokenizer contains an empty string
token.removeLastRaw()
token.Type = WORD_TOKEN
token.Index = t.index
Expand Down Expand Up @@ -422,6 +422,8 @@ func Split(s string) (TokenSlice, error) {
// It quotes and escapes where appropriate.
// TODO experimental
func Join(s []string) string {
// TODO how to handle unsafe content? similar to `url.PathEscape` and unsafe by default?
// TODO how to handle home/named directory expansion?
replacer := strings.NewReplacer(
"$", "\\$",
"`", "\\`",
Expand All @@ -431,7 +433,7 @@ func Join(s []string) string {
for _, arg := range s {
switch {
case arg == "",
strings.ContainsAny(arg, `"' `+"\n\r\t"):
strings.ContainsAny(arg, `"' `+"`$\n\r\t"): // TODO what about pipeline delimiters
formatted = append(formatted, replacer.Replace(fmt.Sprintf("%#v", arg)))
default:
formatted = append(formatted, arg)
Expand Down
17 changes: 17 additions & 0 deletions shlex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,20 @@ func TestSplit(t *testing.T) {
}
}
}

func TestJoin(t *testing.T) {
for expected, words := range map[string][]string{
``: {},
`echo "\$(ls)"`: {"echo", "$(ls)"},
"echo \"\\`ls\\`\"": {"echo", "`ls`"},
"echo \"'ls'\"": {"echo", "'ls'"},
`echo "\"ls\""`: {"echo", `"ls"`},
`echo "\$(ls /tmp)"`: {"echo", "$(ls /tmp)"},
`ls /tmp | xargs -n 1 echo`: {"ls", "/tmp", "|", "xargs", "-n", "1", "echo"},
`echo "one\ntwo"`: {"echo", "one\ntwo"},
} {
if actual := Join(words); actual != expected {
t.Errorf("joined words don't match\nactual : %#v\nexpected: %#v", actual, expected)
}
}
}