diff --git a/expand/expand.go b/expand/expand.go index 10437a51e..8b85bc5c7 100644 --- a/expand/expand.go +++ b/expand/expand.go @@ -414,7 +414,11 @@ func (cfg *Config) wordField(wps []syntax.WordPart, ql quoteLevel) ([]fieldPart, case *syntax.Lit: s := x.Value if i == 0 && ql == quoteNone { - s = cfg.expandUser(s) + if prefix, rest := cfg.expandUser(s); prefix != "" { + // TODO: return two separate fieldParts, + // like in wordFields? + s = prefix + rest + } } if ql == quoteDouble && strings.Contains(s, "\\") { buf := cfg.strBuilder() @@ -509,7 +513,12 @@ func (cfg *Config) wordFields(wps []syntax.WordPart) ([][]fieldPart, error) { case *syntax.Lit: s := x.Value if i == 0 { - s = cfg.expandUser(s) + prefix, rest := cfg.expandUser(s) + curField = append(curField, fieldPart{ + quote: quoteSingle, + val: prefix, + }) + s = rest } if strings.Contains(s, "\\") { buf := cfg.strBuilder() @@ -603,28 +612,27 @@ func (cfg *Config) quotedElems(pe *syntax.ParamExp) []string { return nil } -func (cfg *Config) expandUser(field string) string { +func (cfg *Config) expandUser(field string) (prefix, rest string) { if len(field) == 0 || field[0] != '~' { - return field + return "", field } name := field[1:] - rest := "" if i := strings.Index(name, "/"); i >= 0 { rest = name[i:] name = name[:i] } if name == "" { - return cfg.Env.Get("HOME").String() + rest + return cfg.Env.Get("HOME").String(), rest } if vr := cfg.Env.Get("HOME " + name); vr.IsSet() { - return vr.String() + rest + return vr.String(), rest } u, err := user.Lookup(name) if err != nil { - return field + return "", field } - return u.HomeDir + rest + return u.HomeDir, rest } func findAllIndex(pattern, name string, n int) [][]int { diff --git a/interp/interp_test.go b/interp/interp_test.go index 6c0da1efe..3bdebbd45 100644 --- a/interp/interp_test.go +++ b/interp/interp_test.go @@ -655,6 +655,12 @@ var runTests = []runTest{ {`[[ 'ab\c' == *\\* ]]`, ""}, {`[[ foo/bar == foo* ]]`, ""}, {"[[ a == [ab ]]", "exit status 1"}, + {`HOME='/*'; echo ~; echo "$HOME"`, "/*\n/*\n"}, + {`test -d ~`, ""}, + {`foo=~; test -d $foo`, ""}, + {`foo=~; test -d "$foo"`, ""}, + {`foo='~'; test -d $foo`, "exit status 1"}, + {`foo='~'; [ $foo == '~' ]`, ""}, { `[[ ~ == "$HOME" ]] && [[ ~/foo == "$HOME/foo" ]]`, "", diff --git a/interp/test.go b/interp/test.go index 2fa5db10d..53d8f7579 100644 --- a/interp/test.go +++ b/interp/test.go @@ -20,7 +20,7 @@ import ( func (r *Runner) bashTest(ctx context.Context, expr syntax.TestExpr, classic bool) string { switch x := expr.(type) { case *syntax.Word: - return r.literal(x) + return r.document(x) case *syntax.ParenTest: return r.bashTest(ctx, x.X, classic) case *syntax.BinaryTest: