当前位置:首页 > 文章列表 > Golang > Go教程 > Go Doublestar 怎样用 WithNoFollow 限制符号链接遍历

Go Doublestar 怎样用 WithNoFollow 限制符号链接遍历

来源:17golang原创 2026-10-29 11:39:57 0浏览 收藏

在 Go 中用 Doublestar 递归匹配目录时,如果目录树里存在符号链接,最关键的一行是把 doublestar.WithNoFollow() 作为选项传给 Glob 或 GlobWalk。它会让递归遍历不沿目录符号链接进入目标目录,但不是把路径前缀里的符号链接也变成绝对禁止访问。理解这条边界,才能避免把匹配范围扩大到预期之外。

官方地址:https://github.com/bmatcuk/doublestar

常规做法是用 os.DirFS 固定一个根目录,再用 doublestar.Glob(fsys, "**/*.go", doublestar.WithNoFollow()) 递归匹配。需要特别避开的是:元字符出现以前的固定路径如果本身就是符号链接,Doublestar 仍可能跟随它。

先分清 Glob、FS 和遍历选项

Doublestar v4 基于 io/fs,支持 ** 递归模式;项目当前文档说明 v4 需要 Go 1.16 或更高版本。把宿主机目录交给 os.DirFS 后,Glob 只接收相对于这个 FS 根的模式。这样做的好处是根目录和匹配规则分开,后续更容易审查范围。

本例只关心“递归时不进入目录符号链接”,因此把选项放在 Glob 的最后参数位置:

package main

import (
    "fmt"
    "io/fs"
    "os"

    "github.com/bmatcuk/doublestar/v4"
)

func listGoFiles(root string) ([]string, error) {
    // 把宿主机目录固定为 FS 根,模式中的路径不再直接拼接系统绝对路径。
    fsys := os.DirFS(root)

    // **/*.go 负责递归筛选,WithNoFollow 负责不沿遍历途中遇到的符号链接深入。
    matches, err := doublestar.Glob(fsys, "**/*.go", doublestar.WithNoFollow())
    if err != nil {
        // 坏模式会返回 ErrBadPattern;其他错误是否中止取决于 Glob 选项。
        if err == doublestar.ErrBadPattern {
            return nil, fmt.Errorf("路径模式无效: %w", err)
        }
        return nil, err
    }
    return matches, nil
}

func _keepFSImport(_ fs.FS) {}

示例里的 fs 导入只用于展示 FS 边界时可以怎样保留类型;实际项目如果不需要这个辅助函数,可以直接删除它。关键点是:WithNoFollow 是 GlobOption,不是模式字符串的一部分,也不替代根目录权限控制。

WithNoFollow 到底阻止了哪一段遍历

假设根目录下有普通目录 src,还有指向外部目录的符号链接 vendor-link。对根 FS 使用 ** 或 **/*.go 时,Doublestar 在递归扫描目录项的过程中遇到 vendor-link,不会继续沿它读取目标目录中的内容。结果里仍可能出现这个符号链接本身,具体是否只保留文件项还要看是否叠加 WithFilesOnly。

Doublestar Glob、FS 根目录、WithNoFollow 与符号链接遍历边界的静态结构说明图
图1:结构说明图,展示 Glob、fs.FS 与 WithNoFollow 的静态关系;它不是运行截图或执行证据。

这里的“不要跟随”只描述遍历动作,不等于过滤所有符号链接。如果业务要求结果列表里连符号链接也不能出现,还要结合结果处理或其他匹配条件判断,不能只凭选项名称推断。

最容易误判的是固定前缀符号链接

Doublestar 官方说明了一个重要例外:如果模式在第一个元字符以前已经写出了符号链接路径,例如 path/to/symlink/*,这个固定前缀可能被跟随,前提是它是有效的目录符号链接。相反,path/to/** 的递归部分不会进入该符号链接,path/*/symlink/* 也不会把它当成固定前缀直接打开。

因此,下面两类写法的安全含义不同:

模式形态WithNoFollow 的关注点使用提示
data/**递归遇到 data 下的目录符号链接时不深入适合把根目录作为固定边界
data-link/**data-link 位于元字符前,前缀链接可能被跟随先确认根路径本身是否可信
*/data-link/*链接作为通配匹配得到的目录项处理仍需结合业务允许的目录范围

换句话说,WithNoFollow 解决的是“递归扫描阶段不要沿链接继续走”,并不负责把用户传入的任意根路径转换成沙箱。若根目录来自配置或用户输入,应先在应用层完成允许目录判断,再创建 FS。

需要文件结果时再叠加 WithFilesOnly

WithFilesOnly() 会让 Glob、GlobWalk 或 FilepathGlob 只返回文件。Doublestar 文档对“文件”的定义包含“不是目录,或不是指向目录的符号链接”。当它和 WithNoFollow() 一起使用时,目录符号链接不会被跟随,因此可能作为结果保留下来;这正是很多人第一次组合选项时容易忽略的边界。

func listOnlyFiles(root string) ([]string, error) {
    // 用 DirFS 固定扫描根目录,避免把路径模式和宿主机分隔符混在一起。
    fsys := os.DirFS(root)
    matches, err := doublestar.Glob(
        fsys,
        "**/*",
        // 不深入符号链接,同时把目录项结果收窄到文件语义。
        doublestar.WithNoFollow(),
        doublestar.WithFilesOnly(),
        // 目录读取失败时直接返回,便于上层记录失败而不是静默缺项。
        doublestar.WithFailOnIOErrors(),
    )
    if err != nil {
        return nil, fmt.Errorf("扫描文件失败: %w", err)
    }
    return matches, nil
}
Doublestar 固定路径前缀与元字符边界对符号链接跟随行为的静态关系图
图2:边界说明图,对比固定前缀、递归模式和 WithFilesOnly 的关系;它不是目录扫描截图。

如果只想尽力收集能读到的结果,可以省略 WithFailOnIOErrors,因为 Glob 默认会忽略遍历时的 IO 错误;如果目录内容是配置、备份或审计输入,通常更适合显式返回错误,让调用方知道结果可能不完整。

把这几个判断留在代码评审清单里

  • 根目录是否已经在业务允许范围内,而不是把 WithNoFollow 当成权限隔离。
  • 模式中的第一个元字符在哪里;固定前缀是否可能包含符号链接。
  • 结果需要目录、普通文件,还是允许保留目录符号链接;据此决定是否使用 WithFilesOnly。
  • IO 错误是可忽略的缺项,还是必须让任务失败;据此决定是否使用 WithFailOnIOErrors。
  • 模式是否使用正斜杠;Glob 面向 io/fs,Windows 场景不要把 FilepathGlob 的路径习惯混用进来。

相关问题:WithNoFollow 能否阻止固定根路径的符号链接?不能完全这样理解,官方例外说明固定前缀仍可能被跟随;为什么加了 WithFilesOnly 还看到目录符号链接?因为不跟随时它不被视作目标目录,文档允许它作为文件结果;什么时候用 GlobWalk?当不需要一次性保存全部匹配项,或需要拿到 fs.DirEntry 并提前跳过目录时更合适。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go Doublestar 怎样用 GlobWalk 边遍历边处理匹配项Go Doublestar 怎样用 GlobWalk 边遍历边处理匹配项
上一篇
Go Doublestar 怎样用 GlobWalk 边遍历边处理匹配项
Go Expr 怎样用 Env 为表达式声明结构化输入
下一篇
Go Expr 怎样用 Env 为表达式声明结构化输入
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    773次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    770次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    854次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    821次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    651次使用