
CLI开发工具【免费下载链接】gduFast disk usage analyzer with console interface written in Go项目地址https://gitcode.com/gh_mirrors/gd/gdu点击查看免费下载gduFast disk usage analyzer with console interfaceGo 语言编写的磁盘用量分析器在终端 UI 与 Web UI 中提供了“移入回收站”功能。本文以仓库中的架构决策记录 docs/adr/0002-external-trash-command.md 为骨架系统讲解其外部trash-command的设计动机、/bin/sh求值模型、$1/$/$*占位符规则、以文件系统而非退出码为准的树同步策略并结合 pkg/remove/trash_command.go 源码与 pkg/remove/trash_command_test.go 测试用例逐层印证。读者读完将能理解为何 gdu 不采用 ncdu 的字符串拼接方案并能正确配置自定义回收目录如trash-put --trash-dir或在 macOS 上启用可用的D键。背景内置回收站实现的固定性与用户诉求在引入外部命令之前gdu 的回收站行为是固定的终端 UI 中按D键会把条目移入 FreeDesktop 回收站。内置实现的目标位置固定为$XDG_DATA_HOME/Trash未设置时回退到$HOME/.local/share/Trash见 pkg/remove/trash.go 中的trashDir()并且该实现只存在于非 macOS 的 Unix 平台——darwin 与 Windows 上只有直接报错的 stub。这个固定方案带来了两类现实诉求对应 issue #640自定义回收目录用户希望像 ncdu 的--delete-command那样通过trash-put --trash-dir DIR把文件放入非默认位置的回收站macOS 可用性希望借助trash或gio trash让D键在 macOS 上真正工作起来。ADR 明确说明这是一个用户可配置的逃生通道escape hatch而不是自动探测。在 macOS 上探测trash或gio是否可用仍然是一个开放问题本文描述的工作区方案需要用户自行在配置中指定命令。决策/bin/sh -c command $ gdu abspathADR 给出的核心求值模型是/bin/sh -c command $ gdu abspath这一行拆开看包含三个层次的设计取舍保留 shell以获得展开能力ncdu 的做法是把绝对路径文本拼接到给定字符串末尾然后在 shell 中求值。文本拼接的致命缺陷是名为; rm -rf ~的文件会成为 shell 语法即路径注入。gdu 的决策是保留 shell但把路径作为位置参数传递——/bin/sh -c ... gdu abspath中gdu是$0绝对路径是$1。这样~、$HOME等来自~/.gdu.yaml配置的展开仍然有效这正是“自定义回收目录”选项存在的意义而文件名永远不可能被当作 shell 语法解析。源码中的证据shellBin /bin/sh及其注释明确指出选择 POSIX shell 而非$SHELL是因为命令是按$组装的并非所有交互式 shell 都以相同方式处理它见 pkg/remove/trash_command.go。实现上通过exec.Command(argv0, argv...)直接执行runTrashCommand并刻意保留//nolint:gosec注释说明“运行用户提供的命令正是本功能的目的”。拼接假设的失效mv的反例文本拼接还有一个隐含假设命令在末尾可以接一个参数。这对trash-put和gio trash --成立但对目的地放最后的mv不成立。ADR 记录了真实的用户直觉自然反应是写mv $1 ~/Trash而在无条件的末尾拼接下这条命令会收到两次路径一次来自用户的$1一次来自拼接。gdu 的解法是占位符规则见下文。对应测试 TestTrashCommandWithArguments 验证了带自有参数的命令脚本中$1是命令自带的参数、$2是拼接进来的条目路径二者各归其位。树的更新不依赖退出码第二个问题是“何时把条目从内存树中移除”。gdu 没有逐条目刷新能力只会删除一行而命令是任意的退出码 0 并不意味着条目真的没了。决策是树以文件系统为准更新——命令成功后 gdu 对路径执行lstat只有路径真的不存在了才移除该行。占位符规则$1、$、$*决定路径去向shell 脚本的组装逻辑集中在shellScript函数pkg/remove/trash_command.govar itemPathPlaceholder regexp.MustCompile(\$(?:[1*]|\{1\})) func shellScript(command string) string { if itemPathPlaceholder.MatchString(command) { return command } return command $ }规则可以归纳为两点命令中不含$1/$/$*或${1}时gdu 在命令末尾追加$路径作为位置参数落在末尾。这要求命令必须是以参数结尾的“前缀型”命令gio trash --可以以;结尾或管道命令不行。命令中已通过$1、$、$*引用路径时不再追加路径出现在用户放置的位置——这正是目的地放在最后的命令如mv所需要的。测试用例 TestShellScript 覆盖了全部六种组合命令生成的 shell 脚本trash-puttrash-put $trash-put --trash-dir ~/mytrashtrash-put --trash-dir ~/mytrash $trash-put --trash-dir $HOME/mytrashtrash-put --trash-dir $HOME/mytrash $$HOME不是占位符mv -f $1 ~/mytrash/原样含$1不追加mv -f ${1} ~/mytrash/原样支持花括号形式mv -f $ ~/mytrash/原样含$其中第三行尤其说明占位符的检测粒度$HOME这类无关的 shell 变量不会被误判成路径占位符路径仍然追加。作为代价规则是隐式的——一条出于无关原因包含$的命令永远不会收到路径它什么都删不掉由于树以文件系统为准行只是停留在界面上而不是被静默错误地移除。这是设计上接受的“可见而非静默损坏”。环境变量与执行细节GDU_TRASH_PATH与无终端运行GDU_TRASH_PATH绝对路径除了作为$1传入还会通过环境变量GDU_TRASH_PATH暴露常量定义见 pkg/remove/trash_command.go。实现中envv : append(trashCommandOS.environ(), trashPathEnvVarabsPath)pkg/remove/trash_command.go。测试 TestTrashCommandPassesPathAsArgumentAndEnvVar 用脚本把$#、$1、$GDU_TRASH_PATH全部打印出来断言三者一致恰好 1 个位置参数、且与filepath.Abs得到的绝对路径完全相同。无终端、UI 不挂起命令在没有终端的环境下运行UI 不会挂起因此交互式命令不受支持。这一点在源码注释中反复强调pkg/remove/trash_command.gogdu 在命令执行期间持续渲染 UI开启delete-in-background时甚至可能由后台工作线程执行。实现上cmd.Stdout io.Discard、cmd.Stderr接入缓冲区。错误处理与输出截断命令失败时退出状态和 stderr 内容会进入错误对话框。stderr 通过maxStderrLen 1024截断pkg/remove/trash_command.go避免健谈的命令刷爆错误弹窗func commandError(command string, err error, stderr string) error { msg : strings.TrimSpace(stderr) if len(msg) maxStderrLen { msg msg[:maxStderrLen] ... } if msg { return fmt.Errorf(running trash command %q: %w, command, err) } return fmt.Errorf(running trash command %q: %w: %s, command, err, msg) }对应测试 TestTrashCommandFailingexit 3报错且条目保留、TestTrashCommandFailingWithStderrstderr 文本进入错误信息与 TestTrashCommandStderrTruncated超过 1024 字节被截断并加...。Windows明确不支持Windows 上没有 POSIX shell 可用来求值命令pkg/remove/trash_command_windows.go 中的实现直接返回trash command is not supported on Windows与既有内置回收站 stub 的行为一致。ADR 指出Windows 的回收站Recycle Bin需要SHFileOperation而不是命令行因此这个选项在 Windows 上不带来任何收益。文件系统驱动的一致性命令成功但条目仍在怎么办TrashCommand返回的移除函数完整流程如下pkg/remove/trash_command.gofilepath.Abs求得条目绝对路径失败则直接返回错误见 TestTrashCommandAbsError组装argv : []string{-c, shellScript(command), gdu, absPath}并附带GDU_TRASH_PATH环境变量执行执行失败返回带 stderr 的错误条目保留在树中执行成功lstat该路径——若仍存在返回 nil 且不删除行命令成功但什么都没删如交互式命令答“no”、或拼错成ls之类若确实消失才调用dir.RemoveFile(item)。对应测试 TestTrashCommandLeavingItemInPlace 用true命令模拟“成功但没删”的场景断言文件仍在、行仍在、ItemCount不变。这一设计带来的语义特点值得明确树从不声称已删除但实际未删除的东西。代价是一条成功却没删的坏命令会表现为“按了键却没反应”行静默留在界面上。条目若被移动到别处会从树中删除而不是重新挂接。gdu 不会重扫条目不会在新位置出现——这与 ncdu 的限制相同。只有选中条目会被刷新这是 gdu 缺乏逐条目刷新能力的直接推论configuration.md 中亦有说明。实战配置命令行为、配置样例与常见坑命令行与配置文件选项可在 CLI 与 YAML 配置两个层面设置命令行--trash-command见 cmd/gdu/main.go 中的定义帮助文本示例即trash-put --trash-dir ~/mytrash配置文件Flags结构体中的TrashCommand string \yaml:trash-command[cmd/gdu/app/app.go](https://link.gitcode.com/i/88c1336c3f3a6f905bde0b936f0a7a05)配置文件默认位置为~/.gdu.yaml。应用启动时非空的TrashCommand通过ui.SetTrashCommand(...)注入终端 UIcmd/gdu/app/app.goWeb UI 也有等价的注入路径同文件 #L496-L497。配置文档 configuration.md 对trash-command有完整说明。推荐配置一自定义回收目录trash-command: trash-put --trash-dir ~/mytrash命令不含占位符gdu 追加$。~/mytrash的展开发生在/bin/sh内这正是保留 shell 的原因若用纯 exec 而不经过 shell来自配置文件注意YAML 中的~并不会被 YAML 解析器展开的~就永远不会展开选项便失去了意义。推荐配置二macOS 上用mv做工作区trash-command: mv -f $1 ~/mytrash/$1命中占位符规则路径不再追加落在用户指定的位置结尾的斜杠至关重要没有它当~/mytrash不存在时mv会把条目重命名成~/mytrash悄悄覆盖该路径下原有的东西有它时缺失的回收目录会变成错误对话框。测试 TestTrashCommandWithMvToMissingDir 专门验证了这一行为。也要注意mv与真正的回收工具不同同名文件会被覆盖且不记录任何可恢复原位置的元数据。该配方的完整路径在 TestTrashCommandWithMv 中端到端验证HOME被重定向到临时目录后mv -f $1 ~/mytrash/成功把file2移入$HOME/mytrash且条目从内存树移除。交互式命令与限制速查命令不得是交互式的无终端、UI 不挂起、后台模式下由 worker 执行命令失败时退出状态与截断的stderr 显示在错误对话框中条目保留命令成功但条目仍在磁盘上时条目同样保留在列表中no-delete选项会禁用D键无论是否配置trash-command见 configuration.mdWeb UI 的 “Move to Trash” 动作在同一契约下复用该选项Windows 不支持无 POSIX shell。后果总结设计权衡一览ADR 的 Consequences 部分可以归纳为一张权衡表权衡说明无占位符的命令必须是前缀型gio trash --可行以;结尾或管道命令不可行。但写$1即可解除限制——与 ncdu 不同gdu 始终有出路占位符规则是隐式的为无关原因含$的命令永远收不到路径什么都不删树以文件系统为准行保留在界面上——可见而非静默损坏成功但未删除交互命令答“no”或ls式笔误行静默保留代价是按了看似无效的键但树从不撒谎移动到别处条目从树中删除而非重新挂接无重扫与 ncdu 限制相同macOS用户配置工作区而非自动探测探测trash/gio仍是开放问题Windows无收益Recycle Bin 需要SHFileOperation而非命令行从整体架构看这个 ADR 的核心思想是“用占位符换取安全用文件系统换取真相”保留 shell 但隔离路径免注入让文件系统状态而非退出码决定树的内容免误报。对于需要将 gdu 集成进自定义备份、归档或回收流程的开发者这份设计同时给出了可复制的配置模板与可预期的失败模式。相关阅读gdu 配置文档、命令行手册 gdu.1.md、外部回收站命令实现、测试套件、Windows stub。赞分享CLI开发工具【免费下载链接】gduFast disk usage analyzer with console interface written in Go项目地址https://gitcode.com/gh_mirrors/gd/gdu点击查看免费下载相关推荐Ruflo 架构决策合规审查指南基于 ruflo-adr 插件驱动 ADR 代码一致性检查Ruflo 架构决策合规审查指南基于 ruflo adr 插件驱动 ADR 代码一致性检查 ruflo 将架构决策记录ADR作为团队约定的制度层而人工智能AI Agent多智能体Agent 编排Agent 记忆工具调用代码智能体MCP 服务AI 评测CMake 4.5 新特性详解用 RULE_PATTERNS 文件集属性驱动自定义规则的占位符展开CMake 4.5 新特性详解用 RULE_PATTERNS 文件集属性驱动自定义规则的占位符展开 本篇围绕 CMake 的文件集属性 RULE_PATTER构建工具开发工具CLIVFSForGit Windows 文件系统虚拟化详解ProjFS 驱动、占位符状态机与回调机制VFSForGit Windows 文件系统虚拟化详解ProjFS 驱动、占位符状态机与回调机制 本篇技术指南以 VFSForGit 仓库中的 Windows版本控制开发工具存储上一篇xberg Go 绑定批量 URI 文档抽取实战ExtractBatch 用法、结果结构与底层并发原理下一篇es-toolkit/compat isPlainObject 详解Lodash 兼容版纯对象检测的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考