diff --git a/internal/fnmatch/fnmatch.go b/internal/fnmatch/fnmatch.go index 74a12754e..80ffad795 100644 --- a/internal/fnmatch/fnmatch.go +++ b/internal/fnmatch/fnmatch.go @@ -54,17 +54,22 @@ func Convert(pattern string, flags int) (*regexp.Regexp, error) { pattern = strings.Replace(pattern, "\\?", "[:escapedques:]", -1) pattern = strings.Replace(pattern, "\\.", "[:escapeddot:]", -1) } - pattern = strings.Replace(pattern, ".", "\\.", -1) - pattern = strings.Replace(pattern, "+", "\\+", -1) - pattern = strings.Replace(pattern, "$", "\\$", -1) - pattern = strings.Replace(pattern, "^", "\\^", -1) + + // Characters that are special in regexps but not in glob, must be + // escaped. + for _, char := range []string{".", "+", "$", "^", "(", ")", "|"} { + pattern = strings.Replace(pattern, char, "\\"+char, -1) + } + pattern = strings.Replace(pattern, "**", "[:doublestar:]", -1) pattern = strings.Replace(pattern, "*", any+"*", -1) pattern = strings.Replace(pattern, "[:doublestar:]", ".*", -1) pattern = strings.Replace(pattern, "?", any, -1) + pattern = strings.Replace(pattern, "[:escapedstar:]", "\\*", -1) pattern = strings.Replace(pattern, "[:escapedques:]", "\\?", -1) pattern = strings.Replace(pattern, "[:escapeddot:]", "\\.", -1) + pattern = "^" + pattern + "$" if flags&FNM_CASEFOLD != 0 { pattern = "(?i)" + pattern diff --git a/internal/fnmatch/fnmatch_test.go b/internal/fnmatch/fnmatch_test.go index f12c98591..90b5d52c2 100644 --- a/internal/fnmatch/fnmatch_test.go +++ b/internal/fnmatch/fnmatch_test.go @@ -68,6 +68,10 @@ var testcases = []testcase{ {"hey^hello", "hey^hello", 0, true}, {"hey{hello", "hey{hello", 0, true}, {"hey}hello", "hey}hello", 0, true}, + {"hey(hello", "hey(hello", 0, true}, + {"hey)hello", "hey)hello", 0, true}, + {"hey|hello", "hey|hello", 0, true}, + {"hey|hello", "hey|other", 0, false}, } func TestMatch(t *testing.T) {