ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Windows cmd 实现彩色 ls:三种方案与实战经验总结

Windows cmd 实现彩色 ls:三种方案与实战经验总结 1. 为什么要在 Windows cmd 里折腾一个彩色 lsWindows 的 cmd 从 DOS 时代一路走过来自带的是dir这个命令本身并不差但它默认白底黑字或者黑底白字一个个文件往下排想一眼看出哪个是目录、哪个是可执行文件、哪个是压缩包基本要靠眼睛硬盯。而且大量刚从 Linux/macOS 切回 Windows 的人肌肉记忆还在敲ls结果 cmd 回你一句“不是内部或外部命令”那一下是真的难受。我最初在 Windows 上做运维和开发的时候也想着“反正用 PowerShell 就行”但在生产环境里很多跳板机、老旧服务器、客户现场机器能用的只有原装 cmd。这时候如果能在 cmd 里敲出跟 Unix 一样的ls而且还带颜色体验会舒服非常多。这篇文章就是围绕“Windows cmd 彩色 ls”这个目标把我试过的几种方法、踩过的坑和最终的推荐方案一次性说清楚。先说结论方向Windows 原生 cmd 并没有一个开箱即用的 Unix 风格ls所以实现彩色 ls 通常有三大路线。一是用 doskey 宏把ls映射到 PowerShell 的Get-ChildItem白嫖 PowerShell 的输出和配色二是安装 GNU coreutils如 Git for Windows 自带的工具集拿到真正的ls.exe三是自己写一个ls.cmd包装脚本基于 Windows 自带的 PowerShell 引擎做一套简单的文件类型颜色规则。这三条路各有优劣下面每一章都会给出可复现的步骤也顺便讲清楚背后的原理。整体难度不高新手可以直接照抄老手也可以当个工具清单收藏。2. 先解决底层能力让 cmd 支持 ANSI 颜色输出2.1 cmd 的“上色”机制和 Unix 不一样在 Unix 系统里ls输出彩色文件列表走的是 ANSI 转义序列比如\033[01;32m表示绿色加粗\033[0m表示恢复默认。这种序列本质上是“往标准输出里塞进一段控制字符”终端负责解释它。cmd 原本并不是这样设计的。Windows 的控制台程序包括 cmd 和很多命令行工具默认走的是 Windows 控制台 API比如SetConsoleTextAttribute它一次只能给整行设置一种颜色做不到单行里不同类型文件各自着色。早期 Windows 10 之前的 cmd 基本不支持 ANSI 序列所以你即使往输出里塞控制字符cmd 也只会把那些字符当成乱码显示出来。从 Windows 10 开始微软在 conhost控制台宿主里加入了 VTVirtual Terminal支持cmd 终于能解释 ANSI 转义序列了但这个能力默认不一定开启。这也就引出了第二步。2.2 注册表选项 VirtualTerminalLevel让 cmd 支持 ANSI 颜色最常用的方式是在注册表里给控制台加一个 DWORD 键VirtualTerminalLevel值为1。操作如下reg add HKCU\Console /v VirtualTerminalLevel /t REG_DWORD /d 1 /f执行完成后需要重新打开 cmd 窗口才生效。这个注册表项作用于当前用户的控制台设置只影响 conhost不会影响 Windows Terminal 之类的第三方终端Windows Terminal 默认就开启 ANSI。提示如果注册表修改后某些环境变量没有生效可以再执行一次refreshenv需要安装了 Chocolatey 或使用新终端或者手动重启 cmd。怎么验证 ANSI 是否已经生效我们可以直接在 cmd 里输出一段 ANSI 控制序列。由于在命令提示符里输入 ESC 字符比较麻烦我推荐用下面的方式提取 ESC 字符for /f delims %a in (prompt $E cmd /d) do echo %a[36m彩色文本测试%a[0m如果你在 cmd 窗口里看到“彩色文本测试”变成了青色说明 ANSI 已经可用。如果看到大段怪字符比如←[36m...那说明还没有启用需要检查注册表或者干脆使用 Windows Terminal。另外补一句现在很多系统管理员在 Windows 10 2004 之后的版本上跑脚本发现 cmd 好像本身就支持 ANSI其实是因为某些更新默认开启了一部分。但作为一种可复现的方案我还是建议你手动设置VirtualTerminalLevel保证脏环境里也能跑通。2.3 ANSI 颜色码速查既然要谈彩色 ls就得知道颜色代码怎么写。常见的 ANSI 前景色如下颜色前景码说明黑30一般用于隐藏信息红31可执行文件、错误绿32普通文本、成功提示黄33链接、注意项蓝34目录、普通文件紫/洋红35压缩包、图片等青36软链接或特殊文件白37默认文本使用方法就是ESC[属性;前景色m。比如ESC[1;32m表示绿色加粗ESC[0m表示还原。在 Windows cmd 里属性部分不一定支持得很完美比如加粗在某些老 conhost 上会被忽略但颜色本身基本没问题。3. 方案一零安装用 doskey 让 ls 变成彩色3.1 利用 PowerShell 引擎给 cmd 当外挂Windows 自带 PowerShell在 cmd 里可以直接调用powershell.exe执行命令。PowerShell 的Get-ChildItem输出列表时本身就有默认的着色逻辑目录显示蓝色、可执行文件可能红色或绿色等等。既然我们用不到单独安装任何东西不如让 cmd 的ls直接变成“打开 PowerShell 并执行 Get-ChildItem”。在 cmd 窗口里直接写一行doskey lspowershell -NoProfile -Command Get-ChildItem $*这行的意思是当你在当前 cmd 会话里敲ls时把它替换成powershell -NoProfile -Command Get-ChildItem后面你输入的其他参数会通过$*传递进去。试一下先敲ls如果你当前目录不是空目录你会看到带颜色的目录和文件列表。目录名是蓝色或者青色具体颜色取决于 PowerShell 版本和当前 Windows 控制台配色。再来一个稍微带参数的用法ls -ForcePowerShell 会列出包括隐藏文件在内的所有项目。对于日常浏览目录这个方案基本够用了。3.2 这个方案有哪些明显的短板第一它并不是真正的ls。你输入ls -lPowerShell 不会像 Unix 那样输出一长串权限、属主、大小、时间这样的传统“长格式”因为-l不是 PowerShell 的参数。PowerShell 下想要长格式要写Get-ChildItem | Format-Table或者Get-ChildItem | Format-List这跟 Linux 用户肌肉记忆里的ls -l很不一样。第二doskey 宏只在当前 cmd 会话里有效。你关掉窗口再开一个新的刚才定义的ls就没了。如果你需要每次打开 cmd 都能用需要借助 AutoRun 机制。第三cmd 在调用 PowerShell 时跨进程的颜色传递偶尔会有“时好时坏”的问题。如果你在 PowerShell 里设置过自定义主题比如$PSStyle越复杂越容易在 cmd 里丢失颜色。所以在用方案一的时候建议保持 PowerShell 的默认配置。3.3 让 ls 宏每次打开 cmd 都存在先准备一个批处理文件比如放在C:\Users\你的用户名\cmd_autorun.cmd内容只有一行echo off doskey lspowershell -NoProfile -Command Get-ChildItem $*然后在注册表里设置 AutoRunreg add HKCU\Software\Microsoft\Command Processor /v AutoRun /t REG_SZ /d \C:\Users\你的用户名\cmd_autorun.cmd\ /f之后每次打开 cmd都会先执行这个脚本ls命令就常驻了。注意AutoRun 是一个注册表里的单一字符串值。如果之前你有别的程序或脚本也设置了 AutoRun它会把原来的覆盖掉。稳妥的做法是在那个文件里把所有想开机自动执行的命令都放在一起或者用reg query先看看原来的值是什么。我个人在临时环境里最喜欢用这个方案因为真的零安装而且不太破坏系统整体行为。缺点就是如果你手速快敲了ls -l却发现报错心里多少会咯噔一下。4. 方案二安装真正的 GNU lsGit for Windows / coreutils4.1 为什么这才是“正宗”彩色 ls如果你想要和 Linux 上行为几乎一致的ls那最优解不是让 cmd 去模拟而是直接把 Linux 生态里的 GNU coreutils 拿到 Windows 上来跑。Git for Windows 用户其实早就接触过这套工具在C:\Program Files\Git\usr\bin下面隐藏着一大堆 Unix 命令包括ls.exe、cat.exe、grep.exe、find.exe等等。把真正的ls.exe引入 cmd 之后你能得到什么ls -l长格式输出。ls -a显示隐藏文件。ls -h人类可读大小。ls --colorauto按文件类型自动着色。LS_COLORS环境变量能精细控制每个扩展名的颜色。这一套对从 Linux 迁移到 Windows 的新手或者常年管理混搭环境的运维来说体验提升非常明显。4.2 安装方式Git for Windows 最省事如果你还没装 Git直接下载 Git for Windows 并安装。安装过程一路默认即可。装完后找到ls.exeC:\Program Files\Git\usr\bin\ls.exe --version如果输出类似ls (GNU coreutils) 8.32说明可用。此时你可以在 cmd 里直接敲完整路径测试C:\Program Files\Git\usr\bin\ls.exe --colorauto能看到颜色就算成功。但每次敲完整路径太反人类我们需要在 PATH 里加一个“桥接目录”。4.3 推荐建一个 stub 目录而不是直接把 Git\usr\bin 加进 PATH很多教程会告诉你把C:\Program Files\Git\usr\bin加进 PATH 就行了。我不推荐这么做因为它会把find.exe、sort.exe、grep.exe等一系列 GNU 工具整个暴露在系统的命令搜索路径里。Windows 自带的find.exe和where.exe会跟 GNU 的 find 产生冲突有时候你写批处理脚本用find结果调的是 GNU 版本参数语法完全不一样直接翻车。更稳妥的玩法是创建一个目录比如C:\Users\你的用户名\bin在里面放一个ls.cmd内容如下echo off C:\Program Files\Git\usr\bin\ls.exe --colorauto %*然后把这个目录加到 PATH 里setx PATH %PATH%;C:\Users\你的用户名\bin这样 cmd 里敲ls实际走的是我们指定的ls.exe其他 GNU 工具不会乱入干净又安全。如果你装了 Chocolatey 或者 Scoop也可以直接安装 coreutilschoco install coreutils -y或者scoop install coreutils用 Scoop 安装的相对干净因为工具会被隔离在%USERPROFILE%\scoop\shims下找到ls.exe或ls的 shim参考上面的 stub 方式使用即可。4.4 用 LS_COLORS 自定义文件类型的颜色GNU ls 的颜色不是写死在命令里的而是通过环境变量LS_COLORS控制。每个条目用冒号分隔常见的格式是条目含义di01;34目录directory显示为加粗蓝色ln01;36软链接显示为加粗青色*.zip01;31后缀为.zip的文件显示为加粗红色*.txt0;32后缀为.txt的文件显示为绿色颜色码沿用 Unix termcap 风格30-37 对应黑、红、绿、黄、蓝、紫、青、白属性位1表示加粗4表示下划线。在 cmd 里临时设置set LS_COLORSdi1;34:ln1;36:*.txt0;32:*.exe1;31:*.zip1;35:*.rar1;35:*.7z1;35如果想永久生效用setxsetx LS_COLORS di1;34:ln1;36:*.txt0;32:*.exe1;31:*.zip1;35:*.rar1;35:*.7z1;35在 Linux 上通常用dircolors生成这个变量Windows 没有现成对应。不过你如果装有 Git Bash也可以在 Git Bash 里执行dircolors -b把输出结果复制出来再粘贴到 cmd 的setx里。这样颜色风格会非常接近 Linux 默认效果。这个方案比较适合经常在两套系统之间切换的人。我自己的经验是装完 Git for Windows 后把 stub 文件夹往桌面工具库一放以后不管谁问我“Windows 怎么没有彩色 ls”我都是这一个答案。4.5 关于 --colorauto 和 --coloralways 的区别GNU ls 有三个颜色模式--colornever永远不上色。--colorauto仅当标准输出是终端时才上色。--coloralways无论输出到终端还是文件都强制上色。在 Linux 的 bash 里ls --colorauto是几乎完美的选择。但在 Windows cmd 环境里--colorauto偶尔会因为终端检测逻辑不识别直接不输出颜色。如果遇到这种情况把 stub 文件里的参数改成--coloralwaysecho off C:\Program Files\Git\usr\bin\ls.exe --coloralways %*缺点也有如果你把输出重定向到文件比如ls list.txt文件里会包含 ANSI 转义字符打开看的时候一堆^[[符号。此时就需要手动指定--colornever或者干脆在批处理里做一个分支判断。我的办法是准备两个命令一个ls.cmd用--colorauto一个lsraw.cmd用--colornever重定向的时候用后者省心。5. 方案三写一个纯 cmd / PowerShell 的小包装 ls.cmd5.1 适用场景这个方案适合这么几种情况机器上不方便装 Git不想动注册表去设置 AutoRun又希望在任意一个 cmd 窗口里敲ls就能看到彩色结果。思路也很简单既然 Windows 自带 PowerShell我们就写一个.cmd文件在里面调用 PowerShell 脚本让 PowerShell 帮我们列出文件并给不同扩展名上色。这个文件放在 PATH 里的某个目录以后不管哪个 cmd 窗口都能直接使用。5.2 一个简单但直观的版本先创建一个文件比如C:\Users\你的用户名\bin\ls.cmd内容如下echo off powershell -NoProfile -ExecutionPolicy Bypass -Command $items Get-ChildItem -Force; foreach ($item in $items) { if ($item.PSIsContainer) { Write-Host ([{0}] -f $item.Name) -ForegroundColor Cyan } else { switch -Regex ($item.Extension.ToLower()) { \\.(exe|bat|cmd|com)$ { $c Red } \\.(zip|7z|rar|tar|gz)$ { $c Magenta } \\.(txt|md|log|ini)$ { $c Green } default { $c Gray } }; Write-Host $item.Name -ForegroundColor $c } }这个脚本做了什么Get-ChildItem -Force列出当前目录所有项目包括隐藏文件。如果是目录输出格式为[目录名]颜色是青色。如果是文件会根据扩展名匹配可执行文件显示红色压缩包显示洋红文本文档显示绿色其他显示灰色。效果就是你敲ls后能看到不同类型的文件被清清楚楚分开目录也一眼能认出来。5.3 让这个脚本更接近真实 ls上面这个版本有点简略因为它没有显示文件大小、修改时间、权限这些细节。如果你想用它替代日常文件浏览可以改成调用Format-Table让 PowerShell 自己计算列宽echo off powershell -NoProfile -ExecutionPolicy Bypass -Command Get-ChildItem -Force | Format-Table -AutoSize Mode, LastWriteTime, Length, Name这样输出的格式有点像ls -l而且 PowerShell 默认的配色会在目录名等地方体现。虽然不如 GNU ls 的颜色丰富但总比纯白一片的dir强。如果你愿意再往前一步甚至可以把参数也传进来。比如ls D:\project的时候用 PowerShell 的param($Path)接收路径参数。但这个脚本写起来会膨胀实际使用频率也不是特别高我觉得从“快速解决问题”的角度来看上面两个版本已经足够日常使用了。这里我得提醒一句尽量不要把复杂的目录树遍历逻辑塞进一个.cmd文件里。cmd 解析器对特殊字符很敏感PowerShell 命令写长了一个引号或者反斜杠没处理好整个命令就会莫名报错。如果真需要复杂功能可以考虑写一个.ps1脚本再通过.cmd包装调用。6. 实际体验中的高频问题与排查6.1 输入 ls 提示“不是内部或外部命令”这个最常见。原因也简单doskey 宏没有在当前会话定义或者ls.cmd所在目录不在 PATH 里。排查顺序where ls echo %PATH%如果where ls找不到说明这个命令还没出现在你的 PATH 中。如果用的是 doskey必须在当前窗口中先执行一遍doskey ls...下次新开窗口不会自动存在。6.2 看到一堆 [36m、[0m 之类的字符但没有颜色这是典型的“终端不支持 ANSI 序列”。虽然你输出了控制字符但 cmd 没有解析它们。解决办法是确认VirtualTerminalLevel是否为 1然后重启 cmd。如果你用的是 Windows Terminal默认支持 ANSI可以忽略这一项。也可以先跑一下第 2 章里给的那段“提取 ESC 测试代码”确认当前环境底子有没有问题。6.3 GNU ls 在 cmd 里完全没有颜色如果你用方案二发现ls.exe虽然能列出文件但任何颜色都没有请先换成--coloralways试试C:\Program Files\Git\usr\bin\ls.exe --coloralways如果--coloralways有效说明是--colorauto的文件描述符检测在 conhost 下失灵了。把 wrapper 里的参数改成--coloralways就能解决。还有一种可能你是在某些 SSH 会话、远程 PowerShell 或者 CI 终端里跑这些环境的伪终端pty支持和 Windows 原生 conhost 不同颜色表现自然也会不同。这种情况我通常建议直接改用 Windows Terminal 等现代终端工具。6.4 中文文件名乱码cmd 默认代码页是 GBK936而很多现代工具输出 UTF-8 文件名GNU ls 也不例外。乱码的表现是文件名称显示成鏂囦欢.txt这样。解决方式是切换代码页chcp 65001执行完后再运行ls。注意chcp 65001对某些老程序的兼容性一般比如一些依赖 GBK 的批处理脚本可能在切换后出现字符处理异常。6.5 彩色输出把重定向文件污染了如果强制使用了--coloralways或者某个工具始终输出 ANSI 控制字符当你执行ls filelist.txt时文件内容里会夹带颜色码。如果你需要干净的文件名列表就指定--colornever。方案三中的 PowerShell 包装脚本也会遇到类似情况因为Write-Host输出的颜色信息在重定向下可能会被转换或丢失。6.6 Git\usr\bin 加入 PATH 后find/sort/where 等命令行为变了这个前面也提过GNU 的find.exe、sort.exe语法和 Windows 自带的不一样。如果你把整个Git\usr\bin放到了 PATH 的前面Windows 自带的find工具会被 GNU 版本覆盖很多旧批处理脚本会迅速出错。我的建议始终是不要在全局 PATH 里引入整套 GNU bin用 stub 目录只暴露你需要的ls。另外尽量不要把Git\usr\bin放在C:\Windows\System32之前。如果已经放了建议立即改成 stub 方案这条经验我在日常维护里踩过不少次。6.7 doskey 宏自动消失doskey 宏在两条场景下会消失新开 cmd 窗口或者进入交互式环境里的脚本。想要持久化记得配置 AutoRun。同时注意 AutoRun 本身不能定义多个字符串值所有命令要写在同一个.cmd文件里。7. 不同场景下的最终选择建议如果你问我个人更推荐哪个我会说分场景不要盲目抄一个方案。临时维护别人的电脑不方便装任何软件我会用 doskey 宏方案配合 AutoRun 一次性设置好lspowershell -NoProfile -Command Get-ChildItem $*目的是让用户先有一个能看的彩色列表。虽然参数兼容性一般但胜在零额外包装。如果你是在自己的开发机上长期干活我强烈建议装一个 Git for Windows 或者用包管理器装 coreutils然后建一个ls.cmdstub用真正的 GNUls。这样你从 Linux 环境切回来后不会有认知割裂ls -l、ls -a、ls --color这一套全部能用再加上一个好的LS_COLORS工作效率提升非常明显。还有一种情况是工作机被安全策略限制得死死的连可执行文件都不能随便装到系统目录。这种时候我会把某个用户目录下的自定义bin文件夹加入 PATH然后放一个 PowerShell 包装脚本。它不依赖额外安装任何东西因为在现代 Windows 上 PowerShell 几乎一定存在。缺点是需要维护脚本但脚本本身很简单扩展性强你想改什么颜色都能自己加。最后再说一个小技巧如果你经常需要看一个目录里哪些文件体积最大可以在 GNU ls 方案下执行ls -lSh-S会按文件大小从大到小排序-h会把大小显示成 K、M、G 这种人类可读的单位。这时候再加上彩色标记扫一眼就能定位哪些东西占用空间最大。这是我日常使用频率很高的一条命令比在资源管理器里右键看属性快得多。
返回列表