feach:用 Rust 写一个“在多个目录里执行同一条命令”的小工具


我的机器上有几十个仓库,分散在几个目录里。每次更新都需要逐个执行 cd 和 git pull,为此写过 shell 循环,但在 Windows 上经常被路径和引号的问题打断。后来用 Rust 写了 feach,遍历指定目录的子目录,并在每个子目录中执行同一条命令。

参数设计

参数只有四个:目录、命令、遍历层数、是否并发。命令部分用 clap 的 Vec<String> 配合 num_args = 1..,这样 -c git pull 和 -c "git pull" 都能解析,不需要用户额外加引号。并发开关的字段名写成 r#async,因为 async 从 Rust 2018 起是关键字;clap 会自动把它映射为 --async。

目录遍历

遍历使用 walkdir。max_depth 的语义需要确认:max_depth(1) 会同时包含根目录(深度 0)和一级子目录。默认值 -l 1 因此表示“当前目录加直接子目录”,而不是只处理子目录。这个行为符合我批量更新仓库时的需要,所以没有修改。

follow_links(true) 是为了处理放在软链接后面的仓库。开启后遍历可能走出 --dir 的范围,也可能遇到链接环。walkdir 会把这些情况作为错误返回,但代码里的 filter_map(|r| r.ok()) 把错误全部丢弃了。有一次扫描到没有权限的目录时,工具没有任何提示,我后来才发现错误在这里被吞掉。

命令解析

命令字符串没有交给 sh -c 或 cmd /c,而是自己写了一个简单的分词器,只处理单双引号。原因是 Windows 的 cmd 和 Unix 的 sh 在引号、转义和通配符上的行为差异较大,交给 shell 会导致跨平台行为不一致。这个选择的代价是不支持管道、重定向和 &&,例如 git log | head 无法执行。

执行与输出捕获

执行命令时使用 Command::new().current_dir(),不需要先切换目录,并发执行时工作目录也不会相互影响。最初的实现用 spawn().wait_with_output() 获取输出,但打印出来的只有退出状态。原因是 spawn 默认让子进程继承父进程的 stdio,没有设置为 piped 的流不会被捕获。命令的输出实际上直接写到了终端。

异步模式的问题

异步模式是这部分里问题最多的。最初的实现只有一行 tokio::spawn,实际运行时,部分命令在 main 返回后没有执行完。原因有两个。

第一,tokio::spawn 启动的任务不会被等待。主函数把所有任务提交给运行时后立即返回,#[tokio::main] 生成的运行时会随 main 结束而关闭,未完成的任务被丢弃。

第二,do_command4_dir 内部使用阻塞的 Command::spawn().wait_with_output()。把它放进普通的 tokio::spawn 会占用一个 worker 线程,任务数量增加后线程池会被阻塞,既没有等待结果,也没有实现并发。

后来查文档时了解到 JoinSet 和 spawn_blocking:阻塞调用应该交给阻塞线程池,主函数需要显式等待所有任务结束。仓库里的代码没有修改,仍保留原来的实现。

其他细节

另有一个小问题:Cargo.toml 中的版本是 0.1.2,clap 的 version 却硬编码为 0.1.1,feach -V 显示的是旧版本号。

使用情况

feach 现在仍在日常使用,主要用来批量执行 git pull 和 git status。它的实现很小,但把参数解析、目录遍历、进程执行和异步任务这几个部分放在了一起,也让我对 tokio 的任务生命周期有了更具体的认识。


文章作者: NekokeCore
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 NekokeCore !
 上一篇
Go 实战:用 WebAuthn + PASETO 给后台做一套无密码登录 Go 实战:用 WebAuthn + PASETO 给后台做一套无密码登录
管理后台使用密码登录时,需要处理密码复用、哈希存储、拖库和钓鱼等问题。Passkey 出现之后,我决定把密码从系统中移除,于是写了 fifu-gateway:前面接管理后台,后面代理业务服务,认证统一在网关完成。 架构与信任边界架构比较
2026-06-18
下一篇 
Tauri + Rust 实战:把 Windows 回收站改成啵啵猫 Tauri + Rust 实战:把 Windows 回收站改成啵啵猫
这个项目的目标是把 Windows 回收站的图标换成啵啵猫。选择它主要是想找一个具体场景练习 Tauri,同时了解一下 Windows Shell 图标的配置方式。项目使用 Tauri 1.4、Vue 3 和 TypeScript,Rust
2024-11-05
  目录