1. 先把问题摆清楚:cmd 里为什么不能直接彩色 ls
在 Windows 的 cmd 里敲ls,我相信绝大多数人的反应都是那句经典报错:“'ls' 不是内部或外部命令,也不是可运行的程序或批处理文件。” 如果你是从 Linux 或 macOS 切过来的,或者是平时要在 cmd 里跑 Java、Docker、Elasticsearch 这类服务的后端开发,大概率会特别怀念终端里那个能按文件类型分色的ls。它能让你扫一眼就知道哪个是目录、哪个是可执行文件、哪个是压缩包。Windows 的dir虽然能用,但默认只有一种颜色,信息密度低很多。
这篇就来写我在 Windows 上折腾“彩色 ls”的完整过程。不是只扔一个工具给你,而是把几条可走通的路线都拆开讲:最省事的现代工具方案、接近 Linux 原汁原味的 GNU ls 方案,以及 cmd 里如何做命令映射、如何在脚本和管道场景下让颜色稳定生效。顺带把我踩过的坑、排查过的奇怪问题也写出去,给后来的人省点时间。
1.1 生态不同导致的“没有这个东西”
cmd 里之所以没有ls,根源不是微软“做不出来”,而是 Windows 的命令行生态从一开始就走了一条和 Unix 完全不同的路。Unix/Linux 世界里,ls是系统自带的、约定俗成的目录列表命令;Windows 传承的是 DOS 时代的dir。你当然可以在 cmd 里用dir看到文件列表,但它的选项风格、默认输出格式、是否支持 ANSI 颜色,都和 Unix 工具链是两码事。
更关键的是,就算你把第三方工具放进来了,Windows 的 cmd 也不一定认识。cmd 本身是一个很老的终端宿主程序,它对 ANSI 转义序列的支持是后来补的。也就是说,你想让文件列表五颜六色,需要同时满足三件事:
- 系统里存在一个能输出彩色信息的
ls工具(或者能模拟它); - cmd 或你当前用的终端能解析 ANSI 颜色序列;
- 工具内部有一套“什么文件类型用什么颜色”的规则。
这三件事缺一个,结果就是要么报“不是内部或外部命令”,要么虽然有ls但颜色出不来,要么颜色出来了但乱码。
1.2 三要件:命令、终端、颜色规则
很多人一开始只盯着“找工具”,装完之后发现 cmd 里仍然没有颜色,就开始怀疑是不是下载错了。其实“彩色 ls”的完整链路是这样的:
命令本身决定能不能列出文件,这是第一层。终端决定能不能显示颜色,这是第二层。工具内部的颜色规则决定哪个文件用哪种颜色,这是第三层。我们常说的LS_COLORS环境变量,就是第三层的核心配置文件。Linux 下常见的ls显示目录是蓝色、可执行文件是绿色、压缩包是红色,这些都不是凭空来的,而是通过LS_COLORS或者系统默认配置控制的。
在 Windows 上折腾,你要做的其实是把这条链路补通。下面说的几种方案,本质都是在不同的环节补齐能力。
1.3 三条路线,按需选
先说结论,我建议大多数人在 Windows 上优先用现代工具lsd(LSDeluxe 的缩写),其次是贴近 Linux 习惯的 GNU ls 方案。两个方案各有优势,我也遇到不少同事第一反应是“装个 Git Bash 不就有 ls 了”,这说明 GNU ls 的路子也很有群众基础。
| 路线 | 命令来源 | 颜色机制 | 适合人群 |
|---|---|---|---|
| LSDeluxe | 单独的 exe,从 GitHub 或包管理器下载 | 内置主题,输出自带 ANSI 颜色 | 想要开箱即用、好看、支持图标和 Git 状态的人 |
| GNU ls | Git for Windows / MSYS2 提供的 coreutils | LS_COLORS 环境变量控制 | 习惯 Linux 命令细节、想完全复刻服务器体验的人 |
| 只改命令映射 | 让 ls 指向已有工具 | 取决于映射的底层工具 | 只是想少敲几个字母、不追求颜色的人 |
下面从最直接的路线开始讲。
2. 最直接的路线:安装 LSDeluxe,三分钟点亮彩色 ls
2.1 安装:一条命令搞定
lsd是一个 Rust 写的现代化目录列表工具,兼容 Linux、macOS 和 Windows。它最大的优势是完全独立,不依赖 Git 环境或 MSYS2 那一堆 DLL,拿过来就能用。安装方式很多,我列几个我实际操作过的:
winget install lsd如果 winget 搜索结果里名字太多,可以先搜索:
winget search lsd看到类似lsd-rs.LSDeluxe的条目,再安装对应的 ID 即可。另外两个常用包管理器也能装:
scoop install lsd choco install lsd手动安装也不难。去 lsd 的 GitHub Releases 页面下载 Windows 对应的压缩包,比如lsd-1.x.x-x86_64-pc-windows-msvc.zip,解压后把里面的lsd.exe放到一个你自己的工具目录,比如C:\tools\,然后把这个目录加进系统 PATH。这样在任意 cmd 窗口中都能直接执行lsd命令。
2.2 用 doskey 让 cmd 把 ls 当新命令用
装好之后,你直接执行lsd就能看到彩色输出。但这还差一步,用户习惯敲的是ls,不是lsd。在 cmd 里没有 Linux 那种“别名”概念,它使用的是doskey宏。DOSKEY 可以在交互式命令行里定义“输入 ls 等价于执行 lsd”。
最简单的测试方法,在 cmd 里直接打:
doskey ls=lsd.exe --color=auto $* doskey ll=lsd.exe -l $* doskey la=lsd.exe -a $*这里的$*表示把后面跟的所有参数原样传给lsd。比如你输入ls -la,cmd 会把它展开成lsd.exe --color=auto -la。这种方式最方便,但它只在当前会话有效,关掉窗口就没了。
想永久生效,推荐建一个宏文件。在C:\Users\你的用户名\下新建一个文本文件,比如叫ls_macros.doskey,内容写:
ls=lsd.exe --color=auto $* ll=lsd.exe -l $* la=lsd.exe -a $*然后打开注册表,让每次 cmd 启动时自动加载这个宏文件:
reg add "HKCU\Software\Microsoft\Command Processor" /v AutoRun /t REG_SZ /d "doskey /MacroFile=C:\Users\你的用户名\ls_macros.doskey" /f注意路径里如果有空格,用引号包住,否则 cmd 加载时会出错。加完注册表之后重新打开 cmd,直接敲ls就能看到彩色列表。
提示:DOSKEY 宏只对交互式 cmd 窗口有效。如果你写一个
.bat脚本在脚本里调用ls,DOSKEY 不会生效,因为宏替换发生在键盘输入层面。脚本里要用的命令,优先写成真正的可执行文件路径或批处理。
2.3 调 lsd 的主题和图标
lsd 默认的颜色已经比原生dir好看很多。它把目录、符号链接、可执行文件、套接字、管道等类型都分了色。比颜色更吸引人的是,它默认支持文件类型图标。如果你使用 Windows Terminal 或新版 cmd,通常能看到文件夹、压缩包、脚本文件前带小图标。
图标显示不正常时,多半是字体不支持某些特殊字符。这时候可以去装一个 Nerd Font 字体,然后在 Windows Terminal 的配置文件里把字体改成 Nerd Font,图标就会顺眼很多。
如果你不想用默认主题,可以改 lsd 的配置文件。Windows 上的路径一般是:
%APPDATA%\lsd\config.yaml没有这个文件就自己建一个。我常用的配置是这样的:
classic: false blocks: - permission - size - name color: when: always icons: when: always theme: fancy sorting: dir-grouping: firstcolor.when设成always,强制 lsd 输出颜色,避免在某些终端里因为自动检测失败而丢失颜色。icons.when同理,设成always强制显示图标。sorting.dir-grouping设成first后,目录会排在普通文件前面,这个习惯很贴近 Linux 上常见的显示方式。
3. 想要 Linux 原汁原味:GNU ls + LS_COLORS
LSDeluxe 虽然好看方便,但有些从 Linux 切过来的人,就是怀念那种“标准 ls 参数、标准颜色规则”的感觉。这个时候最好直接用 GNU 的ls,然后把LS_COLORS环境变量配上,让 cmd 也能显示出和 Linux 服务器上一模一样的颜色。
3.1 先有真 ls:Git for Windows 或 MSYS2
Windows 本身没有 GNU ls,想要真 ls,最方便的两个来源:一是 Git for Windows,二是 MSYS2。
Git for Windows 装好之后,在它的安装目录下有一个usr\bin目录,比如:
C:\Program Files\Git\usr\bin这里面有ls.exe、grep.exe、sed.exe等一大票 Unix 工具。把这个目录加到系统 PATH,你在任何 cmd 窗口里敲ls都会运行 GNU ls 了。
MSYS2 也是一样,默认安装在C:\msys64,对应的 Unix 工具目录是:
C:\msys64\usr\bin这两个方案选一个就行。我的个人经验是,Git for Windows 在很多开发者的机器上已经是标配,为了 ls 单独装 MSYS2 有点重。但如果你本来就打算用 MSYS2 做编译环境,那顺手把usr\bin加进 PATH 也顺理成章。
3.2 LS_COLORS 是什么,怎么生成和设置
GNU ls 的颜色规则全部由环境变量LS_COLORS控制。它是一长串用冒号分隔的规则,形如:
di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:ex=01;32:*.tar=01;31:*.gz=01;31:*.zip=01;31:*.jpg=01;35看不懂没关系,先记住两个关键点:
di是目录(directory),ln是符号链接(link),ex是可执行文件(executable);01;34表示“粗体 + 前景蓝色”,01;32表示“粗体 + 前景绿色”,后面的数字是 ANSI 颜色代码。
我自己一般不会手写这串规则。在 Git Bash 或者任意 Linux 环境下,有个命令叫dircolors,它会根据系统配置生成一套可用的LS_COLORS。在 Git Bash 里执行:
dircolors -b输出结果里有一行LS_COLORS='...';。把单引号里面的一大串内容复制出来,然后在 Windows 系统环境变量里新建一个变量,变量名LS_COLORS,变量值粘贴进去,确定保存。之后新开的 cmd 窗口会继承这个变量。
如果你没有dircolors,也可以用 lsd 或网上常见的默认配置。一套能看出明显差异的最小配置大概是这样:
di=01;34:ln=01;36:ex=01;32:*.tar=01;31:*.zip=01;31:*.gz=01;31:*.png=01;35:*.jpg=01;35:*.mp4=01;35这里是让目录显示蓝色、链接显示青色、可执行文件显示绿色、压缩包显示红色、图片视频显示品红。值不够全面,但能立刻感受到“彩色”的差异。
3.3 在 cmd 里稳定输出颜色的实测经验
用 GNU ls 在 cmd 里显示颜色,有一个坑我踩过好几次:ls默认只有在检测到标准输出是终端时,才会启用颜色。它在 Linux 上能正确判断终端,但在 Windows 的 cmd 里判断逻辑不一定可靠。有时候你明明设置了LS_COLORS,在 cmd 里执行ls还是黑白的。
这时候可以加参数强制打开颜色:
ls --color=always如果--color=always输出正常但--color=auto没颜色,说明终端检测出了问题。可以把ls封装成一个自定义命令。比如在宏文件里写:
ls=ls.exe --color=always $*不过我自己不太推荐在 cmd 里长期依赖 GNU ls,因为它的终端检测在原生 cmd 下总有一种“水土不服”的感觉。如果坚持要 GNU ls,我最顺手的用法是把它放在 Git Bash 或 MSYS2 的终端里使用,那里才是它的主场。
3.4 PATH 冲突不能忽略
把C:\Program Files\Git\usr\bin或者C:\msys64\usr\bin加进 PATH,会让一大堆 Unix 工具同时进入 cmd。你得到的不仅是 ls,还有find.exe、sort.exe、grep.exe、awk.exe等几十个程序。
这些工具在正常的 Unix 场景下很好用,但有些名字会和 Windows 自带命令冲突。比如 Windows 里也有find,但功能和 GNU 的find完全不同。一旦 PATH 顺序不对,你输入find的时候可能启动的是 GNU find,导致原本可以用的 Windows 批处理脚本突然行为异常。
注意:如果你只是想要彩色 ls,不建议把整个
usr\bin都加进系统 PATH。更安全的方式是在 macro 或批处理里写死完整路径,比如doskey ls="C:\Program Files\Git\usr\bin\ls.exe" --color=always $*。这样既拿到了 GNU ls,又不污染全局 PATH。
4. 实操中遇到的坑和排查方法
不管用 lsd 还是 GNU ls,实际操作中总会碰到一些奇怪的问题。我把常见症状、可能原因和处理办法整理了一下,做成了速查表。
| 症状 | 可能原因 | 处理办法 |
|---|---|---|
| cmd 里敲 ls 还是提示“不是内部或外部命令” | DOSKEY 宏只在当前会话有效,或宏文件没有加载成功 | 在 cmd 里执行doskey /macros查看当前宏是否加载;检查注册表 AutoRun 路径是否有空格问题 |
| lsd 能运行但没有颜色 | color.when配置为 auto 时检测失败 | 改配置为color: when: always,或在命令里加--color=always |
| lsd 有颜色但图标是乱码 | 字体不支持 Nerd Font 图标 | 换用 Nerd Font 字体,或把 icons.theme 改成 unicode |
| GNU ls 在 cmd 里没颜色 | stdout 不是标准终端或被当成管道处理 | 加--color=always参数 |
| 设置 LS_COLORS 之后没效果 | 工具不是 GNU ls,或环境变量名拼写错误 | 先执行echo %LS_COLORS%确认变量存在;确认执行的是哪个 ls |
| 在脚本/批处理里使用 ls 无效 | DOSKEY 宏不作用于批处理执行环境 | 不要在批处理里依赖 DOSKEY,改用完整路径或独立封装一个目录下的 ls.cmd |
| 加完 usr\bin 后 find/sort 行为异常 | PATH 顺序导致 GNU 工具覆盖 Windows 命令 | 从 PATH 中移除整个 usr\bin,改用宏或批处理指向具体文件 |
4.1 DOSKEY 宏和批处理脚本的边界
很多人折腾完宏之后,写一个.bat文件在脚本里调用ls,发现还是报错。这不是宏写错了,而是 DOSKEY 宏是在命令行解释器读取交互输入时做替换的。批处理文件在执行时并不会经历“键盘输入 → 宏替换”这个过程,所以宏在脚本里无效。
脚本场景下有两个解决办法。一个是写一个真正的ls.cmd,同一个目录下放:
@echo off lsd.exe --color=always %*然后把该目录加进 PATH。但要注意,如果 PATH 里同时存在lsd.exe且系统 PATHEXT 的优先级是.EXE;.BAT;.CMD,你执行ls时 cmd 会优先找到lsd.exe,不会去执行你的ls.cmd。所以这个办法有歧义,我实际更推荐在批处理里直接写lsd或完整路径:
@echo off C:\tools\lsd.exe --color=always %*相比用 cmd 做一层包装,直接调用 exe 更稳定。
4.2 颜色不显示,先检查终端层
颜色不显示时,很多人第一时间去调 lsd 配置或 LS_COLORS,但真正的问题往往是终端没有开启 ANSI 解析。
老版本的 cmd 默认可以不解析 ANSI 颜色序列。如果你的系统还开着旧控制台模式,即使 lsd 输出了 ANSI 代码,你看到的也是满屏的[01;34m之类的乱码,或者干脆没反应。新版 Windows 10 以上大部分控制台默认已经支持 ANSI,但如果你的环境比较特殊,可以手动开启虚拟终端处理:
reg add HKCU\Console /v VirtualTerminalLevel /t REG_DWORD /d 1 /f改完要重新打开 cmd 窗口。这个注册表项的作用是告诉控制台宿主程序,接收并解释 ANSI 转义序列。如果你用的是 Windows Terminal 或 VS Code 内置终端,基本不需要动这个设置,因为这些终端天生支持 ANSI。
4.3 auto 模式不等于 always
--color=auto和--color=always的区别,一定要清楚。auto 模式会判断输出目标是不是终端:如果输出重定向到了文件或者管道,就自动关闭颜色;如果输出目标是终端,就打开颜色。这个设计在 Linux 下很合理,但在 Windows 的某些终端环境下判断容易失误。
我的习惯是,交互式命令用--color=always,确保颜色一定出来。如果是在脚本里,需要把结果重定向到文件,那就不要加强制颜色,不然文件里会混入 ANSI 转义序列。脚本如果要保留颜色结果,建议有意识地用 auto,让工具自己在合适的时机输出颜色。
5. 我的选择和建议
如果让我只留一个方案,我选 LSDeluxe。原因很简单:它是原生支持 Windows 的工具,不用依赖 Git 或 MSYS2 那一套环境,颜色稳定,还附带图标和 Git 状态展示,对日常在 Windows 上折腾的开发者来说体验最现代化。
但如果你是从 Linux 切过来的老手,平时大量操作都在服务器上,我建议多花点时间熟悉LS_COLORS的规则。因为你在 Linux 上配置的文件颜色标注习惯,可以通过同一套环境变量平移到 Windows 的 GNU ls 上,两边保持一致,不用记忆两套规则。
最后分享一个我自己觉得挺实用的小技巧:不管是 lsd 还是 GNU ls,都建议把常用的几个组合一次性写进 DOSKEY 宏文件:
ls=lsd.exe --color=auto $* ll=lsd.exe -l $* la=lsd.exe -a $* lt=lsd.exe --tree $*这样你在 cmd 里可以当作在 Linux 上有一半的手感。慢慢你会发现,Windows 的命令行并没有想象中那么封闭,缺的只是把 Unix 工具链和 Windows 控制台之间的路打通而已。