检查给定路径是否是 golang 中另一个路径的子目录

check if given path is a subdirectory of another in golang

假设我们有两条路径:

c:\foo\bar\bazc:\foo\bar

有什么 package/method 可以帮助我确定一个目录是否是另一个目录的子目录吗?我正在寻找跨平台选项。

您可以尝试使用 path.filepath.Rel():

func Rel(basepath, targpath string) (string, error)

Rel returns a relative path that is lexically equivalent to targpath when joined to basepath with an intervening separator.
That is, Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself

这意味着Rel("c:\foo\bar", "c:\foo\bar\baz")应该是baz,意思是一个完全包含在c:\foo\bar\baz中的子路径,并且没有任何'../'。
这同样适用于 unix 路径。

这将使 c:\foo\bar\baz 成为 c:\foo\bar 的子目录。

您可以使用函数path.filepath.Match()

Match reports whether name matches the shell file name pattern.

例如:

pattern := "C:\foo\bar" + string(filepath.Separator) + "*"
matched, err := filepath.Match(pattern, "C:\foo\bar\baz")

其中 matched 应该是 true

我还没有找到适用于所有类型路径的可靠解决方案,但您可以获得的最佳解决方案是按照 VonC 的建议使用 filepath.Rel

如果两个文件路径都是绝对路径或相对路径(不允许混合),它会起作用,并且在 Windows 和 Linux 上都起作用:

func SubElem(parent, sub string) (bool, error) {
    up := ".." + string(os.PathSeparator)

    // path-comparisons using filepath.Abs don't work reliably according to docs (no unique representation).
    rel, err := filepath.Rel(parent, sub)
    if err != nil {
        return false, err
    }
    if !strings.HasPrefix(rel, up) && rel != ".." {
        return true, nil
    }
    return false, nil
}

以驱动器号开头的绝对 windows 路径需要额外检查。

试试这个代码。这将检查其中一个是否是另一个的子目录。尝试更改 base 和 path 的值,结果应该有效。

package main

import (
    "fmt"
    "path/filepath"
    "strings"
)

func main() {
    base := "/b/c/"
    path := "/a/b/c/d"

    if len(base) > len(path) {
        base, path = path, base
    }

    rel, err := filepath.Rel(base, path)
    fmt.Printf("Base %q: Path %q: Rel %q Err %v\n", base, path, rel, err)
    if err != nil {
        fmt.Println("PROCEED")
        return
    }

    if strings.Contains(rel, "..") {
        fmt.Println("PROCEED")
        return
    }

    fmt.Println("DENY")
}

如果您首先通过对它们调用 filepath.EvalSymlinks()filepath.Abs() 来规范化这两个路径,您可以简单地在每个路径上附加一个“/”,因为 UNIX 内核本身禁止在其中使用“/”路径组件。此时,您可以简单地在两条路径上以任意顺序使用 strings.HasPrefix()