免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

Windows dir /s命令详解:递归遍历与文件批量管理实战

Windows dir /s命令详解:递归遍历与文件批量管理实战 很多人可能觉得dir /s这种命令太基础了基础到都不值得单独拿出来讲。但我干了这么多年运维和开发经常发现一个现象越是天天在用的命令越容易被人忽略掉它真正厉害的地方。dir /s就是这么个玩意儿——平时大家只拿它列个目录觉得“就这”真到了要找文件、清磁盘、对账目、写批处理脚本的时候你才发现它简直是个隐藏的全能选手。我甚至跟同事开玩笑说Windows 命令行里如果只让我留一条命令我可能不选ping不选ipconfig而是选dir /s。这篇文章我不打算讲什么高深的理论就是想从一个实际干活的人的角度把dir /s这个“神奇的存在”从头到尾捋一遍它到底是怎么工作的怎么用才能效率最高哪些场景下会坑你以及怎么用组合拳把它玩出花来。不管你是个刚接触命令行的新手还是写脚本写到吐的老油条我相信总能从里面找到点有用的东西。1. dir /s到底做了什么1.1 一个递归参数把“看目录”变成了“扫全盘”很多人第一次接触dir /s的体验往往是这样在某个目录下敲了一个dir /s结果屏幕上哗啦啦滚出来几百行上千行输出里面不仅有当前目录的文件还有所有子目录以及子目录里的子目录的文件。那一瞬间你会觉得哦这命令是递归了。本质就是这么简单。dir本身是 list directory contents 的意思它的默认行为是只看当前目录这一层不往下钻。而/s这个开关官方解释是“Lists all occurrences of the specified file name within the specified directory and all subdirectories.” 翻译成人话就是不光是当前目录当前目录下面挂的每一层子目录全都给遍历一遍把所有匹配的文件和目录都列出来。其实这个设计在当年非常超前。在图形界面还不普及的年代你想知道一个目录树里到底有哪些文件只有一个办法——一层一层地cd进去然后一次一次地dir看到眼睛花。有了/s之后一次遍历就全出来了。即便放在今天你在资源管理器里搜索文件底层逻辑本质上也是“递归遍历目录树”只是图形界面帮你把结果做了分类和过滤而dir /s是把原始结果一股脑倒给你。我举一个最直观的例子。你想知道D:\projects下所有test文件不管嵌套在哪一层都在哪里一般的做法是打开资源管理器在搜索框输入test等它慢慢转圈。用命令行的话就是一条命令的事dir /s /b D:\projects\*test*这个/b参数也很关键它表示“只要文件路径不要多余信息”后面我会细讲。配合/s使用的时候输出会变成一个纯路径清单非常干净甚至可以重定向到文件里做进一步处理。1.2 和普通dir相比输出结构有什么不同正常情况下dir的输出包含卷标、目录路径、文件列表、文件大小、日期、文件数统计、可用字节数等。加上/s之后你会在每一层子目录的开头重新看到一个该目录的路径头然后是文件列表最后还会在整体输出结束时给出所有文件的汇总统计。比如你在一个包含三个子目录的目录里执行dir /s输出大概会是这样的结构驱动器 D 中的卷是 Data 卷的序列号是 XXXX-XXXX D:\test 的目录 2024/01/10 14:32 DIR sub1 2024/01/10 14:33 DIR sub2 2024/01/10 14:35 2,048 a.txt D:\test\sub1 的目录 2024/01/10 15:00 3,072 b.log D:\test\sub2 的目录 2024/01/10 15:30 58 c.ini 总计文件数3 个文件 总计大小5,178 字节注意最后那里有个“总计”统计这个是dir /s区别于普通dir的重要标志。它会把所有子目录里的文件全部加在一起算出一个总数和总大小。这个特性在统计磁盘占用、清点文件数量的时候特别有用。1.3 不只是递归几个常用参数搭配既然聊到了参数就顺便把几个高频组合一起说了。/s虽然是主角但很多时候它需要别的参数配合才能发挥最大威力。/b极简模式只列出路径。配合/s使用效果最好因为输出会变成一行一个完整路径方便后续用find、findstr过滤或者重定向到文本文件。/a带属性过滤。比如/a:d只看目录/a:-d只看文件去掉目录/a:h看隐藏文件。当你用/s递归的时候/a:d能帮你把整个目录树的目录结构单独拎出来。/o排序。/o:n按文件名排序/o:s按大小排序/o:-s按大小倒序大的在前。如果你想找出某个目录树里最大的几个文件dir /s /b /o:-s然后配合more或者findstr就非常方便。/t指定显示或排序的时间字段。/t:w是最后写入时间/t:a是最后访问时间/t:c是创建时间。默认是最后写入时间w。/4显示四位年份。老版本的 Windows 在默认设置下年份是两位的加上/4会变成2024这种完整格式。现在新系统基本默认四位但如果你的命令脚本要兼容旧机器还是建议加上。讲真dir /s /b /a:-d /o:-s这样的组合我几乎天天都会敲。它能帮我快速判断一个目录下哪些大文件占据了绝大部分空间在排查“C盘怎么又满了”这种问题时效率远超图形界面的逐个文件夹查看。2. 实战场景用dir /s解决的真实问题2.1 快速查找定位文件秒杀资源管理器我最早被dir /s圈粉就是在一次找文件的过程中。当时公司一台服务器上部署了一个老旧的 ASP.NET 站点几十个虚拟目录站点目录结构嵌套至少有五六层深。有一个配置文件connection.config被多个子站点引用有天突然有人改了数据库连接串然后整个系统连不上库了。问题是这个配置文件被复制到了很多子目录里而且不是每个子目录都在用同一个版本运维那边想确认到底哪些目录下有这个文件哪些文件是最新的。打开资源管理器搜索connection.config结果那叫一个慢还经常因为索引没建好、文件权限受限等原因漏掉文件。后来我直接在命令行敲了一条dir /s /b D:\WebSites\connection.config不到两秒钟所有包含connection.config的完整路径全部列了出来每一个副本的位置一目了然。接着再对所有副本执行一次fc对比不到两分钟就定位到了问题。这个套路我后来用过无数次。不管是在 Windows 服务器上还是在自己本地电脑上只要是“明明记得有某个文件但不知道它躲在哪个角落”的场景dir /s /b 盘符:\目录\文件名永远是最快、最稳的答案。配合通配符你还可以模糊搜索dir /s /b C:\Users\admin\*.pdf这条命令会把C:\Users\admin目录下所有层级的 PDF 文件全部找出来。比资源管理器自带的搜索靠谱多了至少它不会因为索引没建好而搜不出东西。2.2 统计文件数量和目录大小容量规划的参考依据很多刚入行的朋友问我怎么快速统计一个目录下有多少个文件、总共有多大。他们会去下载各种第三方工具比如 TreeSize、SpaceSniffer 之类的。这些工具确实强大但如果你只是想知道个大概数值完全没必要引入额外依赖dir /s自带统计功能。dir /s D:\logs执行完之后最后几行会明确告诉你总计文件数18432 个文件 总计大小1,284,378,624 字节简单算一下1.28GB 左右。然后你想对比哪个子目录占得最多可以先用/s看整体再对各个一级子目录分别执行一次dir /s对比大小。虽然这个方法没有 TreeSize 那种可视化圆环图直观但在服务器上你不可能随便装图形工具命令行反而是最通用的方案。值得注意的是dir /s统计的大小是文件的逻辑大小不是磁盘占用大小即不是簇对齐后的实际占用。如果磁盘上有大量小文件实际占用会略大于文件总大小。不过在大多数场景下这个误差可以忽略不计。真要精确到簇级别得用fsutil之类的工具那就超纲了。2.3 批量场景用 for 循环配合 /s 遍历文件dir /s单独用是“看”但一旦放进批处理脚本或者配合for命令它就成了一个强大的“遍历引擎”。举个例子我要在E:\uploads里找出所有 30 天没被修改过的.tmp临时文件然后删掉它们。用dir /s加for就能很干净地实现for /f delims %%i in (dir /s /b E:\uploads\*.tmp) do ( echo %%i )把echo换成del %%i就是批量删除。在写脚本前建议先跑一遍只echo不del确认清单没问题再动真格的。我在实际项目里做过一个日志清理脚本从一堆子目录里把 15 天前的.log文件全部归档压缩核心逻辑就是dir /s /b拿到完整文件列表然后循环处理。再举一个例子你有一个代码仓库的目录树里面有各种各样的.md文档你想把所有文档里包含某个关键字的位置找出来。可以把dir /s和findstr串联起来for /f delims %i in (dir /s /b D:\repo\*.md) do findstr /n TODO %i在命令行直接执行的话%i写一个百分号在批处理文件里要写成%%i。这个细节很多人容易踩坑我专门遇到过同事在.bat里写%i导致变量不展开执行结果莫名其妙。所以说别看命令简单细节决定成败。2.4 输出重定向把文件清单落盘存档dir /s还有一个高频用途是生成目录树文件清单。比如你要给客户交付一批代码同时要附带一个文件清单.txt说明所有交付了哪些文件。图形界面下你想导出一份完整的文件列表通常得借助第三方工具但在命令行下就是一句dir /s /b D:\delivery filelist.txt如果你需要连文件大小、日期一起记录就把/b去掉直接dir /s D:\delivery filelist.txt。一个结构完整、包含各级目录和文件详情的清单就生成了。这种文件清单我建议重定向成 CSV 或文本文件后再用 Excel 打开处理。比如dir /s /b生成的是纯路径你可以用文本编辑器的替换功能把内容转换成相对路径、提取文件名、生成超链接非常灵活。有一次我在做服务器文件移交的时候甲方要求提供所有文件指纹我就是先dir /s /b生成清单然后用 PowerShell 批量计算哈希最后汇总成表格。整个过程一气呵成甲方还夸我说效率高。3. 踩坑实录dir /s的几大“坑”3.1 性能问题文件多到爆炸时的“卡死”体验dir /s最大的痛点就是性能。在机械硬盘时代一个包含几十万小文件的目录执行一次dir /s可能要等上几分钟甚至十几分钟。即便是现在用 NVMe 固态硬盘如果文件数量特别大输出到屏幕依然会非常慢——因为控制台渲染本身也是一个开销很大的操作。我自己遇到的最极端一次是在一台老的 Windows Server 2008 上清查一个文件服务器目录。那个目录下面有接近 80 万个文件执行dir /s /b跑了二十多分钟才出结果。等得我一度以为命令挂掉了差点 CtrlC。后来学聪明了遇到这种超大规模目录我会直接把输出重定向到文件比如dir /s /b D:\huge_dir huge_filelist.txt重定向到文件后少了控制台绘制文本的开销速度会明显提升。再用more huge_filelist.txt分页查看或者用find在文件里搜索这样处理起来更舒服。另外如果你明确知道目标只会出现在前几层目录可以不用dir /s而是手动多写几个通配符目录层级。比如dir /b D:\data\*\*\*.confWindows 命令行的通配符本身就支持跨层匹配尽管不是完整递归有些场景下比/s更快因为少了系统级的递归枚举逻辑。3.2 权限和隐藏文件“找不到”不代表不存在dir /s递归遍历时一旦遇到没有权限访问的子目录会直接报 “拒绝访问” 之类的错误然后继续往下跑。这个行为有时候会产生误导——你以为这个目录下没有你要找的文件其实是因为包含该文件的子目录你没有权限看被略过了。我记得有一次在排查服务器上的文件时用dir /s /b搜索某个 DLL怎么搜都搜不到。结果后来用管理员身份打开命令行重新执行一下子就出来了。原因就是当前用户对某个子目录没有读取权限而被无权限的目录恰恰是那个 DLL 所在的位置。所以用dir /s做全盘搜索时一定记得优先用管理员权限运行命令行特别是搜索系统盘C 盘时。输出中如果夹着 “Access is denied” 之类的错误信息先不要急着下结论。要么换个权限更高的账户重跑要么在命令里加上2nul把错误输出丢弃保持清单干净。所谓“找不到”要区分是“真不存在”还是“无权限访问被跳过了”。还有隐藏文件的问题。默认情况下dir是不会显示隐藏文件和系统文件的除非你开启了显示隐藏文件/s也一样。如果你在找的是隐藏文件或系统文件记得加/a参数比如dir /s /b /a D:\Data\*secret*不加/a隐藏文件就算存在也可能会“隐身”。这个坑很多人会遇到明明文件放在那里搜了半天就是没有怀疑人生。3.3 长路径和中文名的兼容性Windows 的传统路径长度限制是 260 个字符即MAX_PATH。当一个目录树嵌套很深或者目录名、文件名特别长的时候dir /s有可能会在中途“断掉”或者在输出里显示截断的短文件名8.3 格式。在旧版 WindowsWin7、Win2008上这个问题尤其明显。我自己在管理一个自动化构建服务器时就遇到过几次因为构建产物目录路径过长导致dir /s /b输出结果里出现不完整的文件名。后来查了一下这不是dir本身坏了而是 Windows 对路径长度的限制在起作用。解决办法有这么几个方向尽量把要遍历的目录结构扁平化不要嵌套太深这也是一个通用的文件管理建议。用 PowerShell 的Get-ChildItem -Recurse替代。PowerShell 对长路径的支持更好尤其在新版 .NET 运行时里很多长路径问题已经被绕过了。如果必须用 cmd可以开启 Windows 10/11 的“长路径支持”策略gpedit.msc→ “计算机配置” → “管理模板” → “系统” → “文件系统” → 启用Win32 长路径。中文文件名在大多数情况下没问题但要注意 cmd 默认的代码页。如果系统区域设置是英文而目录里又是中文文件名控制台输出的中文可能会显示成乱码。这种情况执行一下chcp 65001把代码页切到 UTF-8再执行dir /s通常就能正常显示了。另外一个办法是直接用 PowerShell它对 Unicode 的处理比 cmd 好得多。3.4 符号链接、联接与递归陷阱Windows 下有两种“假目录”一种是符号链接Symbolic Link一种是目录联接Junction。它们在资源管理器里看起来就像普通文件夹用dir /s遍历时也会被当成目录来处理。但问题在于如果你创建了一个指向父目录的联接dir /s递归时就可能陷入“自己找自己”的诡异局面。举个例子D:\test\link联接指向D:\test那么当你执行dir /s D:\test时Windows 会进入link发现里面有link再进入又发现里面还有link……理论上这会无限递归下去。好在微软从某个版本开始对这种递归链接做了检测会在反复跳转后报错或者直接略过但如果你用的是老系统还是会遇到“命令跑到一半卡死”的情况。在实际使用中我一般会建议在做全盘递归时先用dir /s /b /a:d看看目录树里有没有可疑的符号链接或联接或者在执行前使用dir /a:l检查一下异常条目。当然最稳妥的方法还是交给 PowerShell用Get-ChildItem -Recurse -Attributes ReparsePoint专门筛查这些特殊目录。4. 进阶玩法把dir /s用到极致4.1 管道组合拳过滤、排序、计数一起做dir /s输出结果太冗长往往不直接看全部而是要进行二次过滤。最经典的组合是dir /s /b配合find/findstr。比如你想在某个代码仓库里找出所有引用了某张图片资源的地方而图片路径中带有assetsdir /s /b D:\workspace\src | findstr /i assets这会把D:\workspace\src下所有路径里包含assets的条目过滤出来。/i表示忽略大小写Windows 下找文件不区分大小写但路径字符串的包含关系还是要分清大小写的加上-i更保险。如果你只想数一下某个目录树下一共有多少个.cpp文件可以用dir /s /b D:\code\*.cpp | find /c .cppfind /c会输出匹配行数。这是我最常用的“快速文件计数”方法比数屏显列表快得多。还有排序需求。比如想找出某个目录下最大的 10 个文件dir /s /b /a:-d D:\data | sort等等这里用的是sort但它只能按文件名字符串排序不能按大小排。按大小排序需要借助其他办法。下面这段 PowerShell 就更直接Get-ChildItem -Path D:\data -Recurse -File | Sort-Object Length -Descending | Select-Object -First 10 FullName, Length不过如果只能用 cmd也有个替代思路用dir /s /a:-d得到带大小的完整输出然后手动把输出重定向到文本文件再用 Excel / Vim / 编辑器按列排序。虽然不够优雅但至少能用。4.2 Shell脚本里的“活力四射”循环批处理脚本里for /f配合dir /s /b几乎可以组合出任何文件批量操作。我再分享一个经验做文件批量移动时务必考虑“先列清单再操作”。比如你要把D:\source下所有.png图片移动到D:\target直接写脚本很容易出问题——在遍历过程中移动文件导致目录结构变化。更稳妥的方式是先dir /s /b把结果存到一个临时文件然后for /f逐行读取这个临时文件执行操作dir /s /b D:\source\*.png imglist.tmp for /f delims %%i in (imglist.tmp) do move %%i D:\target\ del imglist.tmp这样一来即使移动过程中目录结构发生变化清单已经固定了循环不会因为目录读取不到而中断。这个思路同样适用于“复制满足特定条件的文件”“把某些文件压缩”等大量场景。注意字符串里如果有空格必须用引号把%%i包起来否则文件路径会被拆成多段命令直接出错。这是我见过的最常见的批处理翻车原因没有之一。4.3 定时任务里的文件巡检dir /s还可以和 Windows 计划任务组合实现简单的文件巡检。举个例子公司内部的文件服务器上每天会生成大量报表文件需要确认“是否按时生成了”“是否存在缺失日期”。我写过一个很粗糙但实用的巡检脚本核心思路是用dir /s /b生成当天所有文件清单。用findstr过滤出关键的报表文件名。把结果数量和预设值做比较如果不一致就通过邮件发送一封告警配合blat或 PowerShellSend-MailMessage。虽然这个方案不如专门的监控平台专业但在轻量级场景下非常够用而且零成本。dir /s提供了一个最原始、最可靠的文件系统快照能力这是各种高级监控工具的地基。4.4 一套顺手的命令速查表最后整理一个我平时最常敲的dir /s命令速查表方便直接抄作业目标命令递归列出目录所有文件dir /s只看文件路径不看其他dir /s /b递归搜索指定文件名dir /s /b D:\目标目录\文件名模糊搜索某类扩展名dir /s /b D:\目标目录\*.log统计文件总数和总大小dir /s D:\目标目录看最后统计找出所有子目录列表dir /s /b /a:d D:\目标目录防止隐藏文件被漏掉dir /s /b /a D:\目标目录按大小倒序排文件并取前10PowerShell:Get-ChildItem -Recurse -File | Sort-Object Length -Descending | Select -First 10导出完整文件清单dir /s /b D:\目标目录 filelist.txt行文至此dir /s在我心里的分量也讲得差不多了。说起这个命令我个人最大的感触是工具不分高低真正拉开差距的是你对工具边界的理解。很多人觉得dir /s简单大概率是因为只拿它当“一个能递归的 dir”来用当你把它和/b、/a、/o、重定向、for /f、findstr组合起来之后它就不再是一个“查看命令”而是一个小型的文件系统批处理引擎。最后再分享一个个人的习惯凡是涉及批量删除或移动文件的脚本我都会先用dir /s /b把目标清单生成出来人工扫一眼确认无误再进入下一步。别嫌麻烦这个习惯救过我很多次也建议你保留。
返回列表