简介:这是一份面向 Linux 运维、开发者与初学者的 tree 命令安装资源。tree 是常用的递归目录列表工具,能以缩进树形结构清晰展示目录层次,适合在 CentOS 等 Linux 环境中快速梳理项目目录、检查文件分布;对不熟悉目录结构的新手,tree 比 ls -R 更直观,对运维人员也是排查部署目录的有效工具。若系统未自带该命令,可直接用包内源码编译部署。资源为 tree-1.7.0 的 tgz 压缩包,共 19 个文件,核心是 8 个 C 源码文件,配合 Makefile、tree.h 头文件以及 INSTALL、README、CHANGES、LICENSE 等工程文档,另含 tree.1 与 tree.1.fr 手册页,整体仅 57KB,轻量便于留存备查。源码中 color.c、html.c、xml.c、json.c 等模块,可帮助理解 tree 的颜色高亮、HTML/XML/JSON 输出等扩展能力,构建脚本与文档也便于二次修改。已有 4483 人学习下载,适合需要系统掌握编译安装流程、了解 tree 内部实现或定制目录展示效果的中初级 Linux 用户。
1. 让目录结构一目了然的 tree 命令:装之前先搞懂它解决什么问题
如果你管过一台稍微像样点的 Linux 服务器,一定有过这样的经历:用ls -R递归看目录,输出能把你眼睛看花;用find查文件,路径一串串往外冒,就是看不出项目整体长什么样。tree命令解决的正是这个痛点——它把目录结构画成一棵倒挂的树,子目录、文件层级、权限、大小全部可视化。运维排查项目结构、写文档前梳理目录、接手别人留下的代码仓库,这三件事里只要碰上一件,你就需要 tree。
tree 本身不是 Linux 内核自带的工具,多数发行版默认不安装。它的安装方式因发行版而异,还牵扯到 rpm 包、源码编译和乱码等一堆细节。这篇文章就沿着「先弄清安装思路 → 再掌握参数用法 → 最后避开常见坑」这条线,把 tree 命令一次讲透,保证你照着做完,在 CentOS、Ubuntu 甚至内网环境下都能用起来。
2. 按发行版各就各位:apt/dnf/yum 在线安装与最小可用验证
2.1 Ubuntu/Debian 系:一条 apt 命令装完,先确认源里有没有
在 Ubuntu 或 Debian 上装 tree 是最省心的。大多数情况下,软件源里直接就有这个包,不需要额外添加任何第三方仓库。执行安装前,我习惯先刷新一下软件源缓存,避免装到一个过期的索引导致版本不匹配。
sudo apt update sudo apt install tree -y第一行apt update的作用是拉取源里最新的软件包列表,让apt知道自己能装什么、什么版本;第二行的-y参数代表跳过交互式确认,安装过程不再询问「Do you want to continue?」。合起来是运维里最常见的「先更新索引再装包」组合。
装完后建议立刻验证一下能不能用:
tree --version如果输出类似tree v2.1.0 (c) 1996 - 2022 by Steve Baker, Thomas Moore, Francesc Rocher, Florian Sesser, Kyosuke Tokoro这样的版本信息,说明安装成功。此时在任意目录直接输入tree,就能看到当前目录的树状结构。如果提示command not found,多半是源里没有这个包,可以换用源码编译的方式,这个在下一章专门讲。
2.2 CentOS/RHEL 系:yum 和 dnf 的差异要分清
CentOS 7 及更早版本默认用yum,CentOS 8 之后逐渐切到dnf。两者参数几乎一致,但底层依赖解析器不同,混用一般也不出问题。在 CentOS 上装 tree,命令如下:
sudo yum install tree -ysudo dnf install tree -y有人会问:极简安装的 CentOS 镜像(比如容器镜像)里可能连yum都没有,更不用说 tree 了。这种情况的处理思路是:先确认网络通不通,再确认源配置有没有问题。一种常见做法是直接用curl拉取阿里云或华为云的镜像源配置文件覆盖默认源,然后再执行安装。这一步看似与 tree 无关,但实际运维中「装不上」的根因八九成在源上,而不是在 tree 本身。
2.3 验证安装:三个命令确认「真的能用了」
很多人装完只敲一次tree --version就算完事,其实这在生产环境里是不够的。我更建议做三连验证:
which tree tree --version tree /tmpwhich tree确认可执行文件在 PATH 里;tree --version确认版本号,方便排查后续问题;tree /tmp则直接跑一次真实输出,看终端有没有乱码、权限报错等隐性错误。如果 /tmp 下文件多,输出会比较长,可以加-L 1只显示一层,这属于参数细节,后面会讲到。
这里有一个容易忽略的点:有些系统管理员为了安全会把/tmp挂载为noexec,如果 tree 恰好被解压放在 /tmp 下运行,就会直接报Permission denied。所以验证时别只测 /tmp,最好在自己常用的工作目录下也跑一次。
3. Linux Tree命令安装文件的离线安装:rpm 包与源码编译的实操路径
3.1 内网环境怎么办:rpm 包下载与本地安装
生产环境里有大量服务器是不通外网的,或者出于安全策略不允许直接访问互联网。这时候安装 tree 就需要走「离线安装」这条路,也就是准备好安装文件再拷进去。tree 命令的官方发行渠道其实非常单一,你不需要去什么奇奇怪怪的网站下载,只要锁定系统对应的 rpm 包就行。
在 CentOS 7 上,常见的操作是找一台同版本且能联网的机器,用yumdownloader把 rpm 包拉下来:
yum install -y yum-utils yumdownloader tree第一条命令安装yum-utils工具集,目的是获得yumdownloader这个下载命令;第二条命令会把 tree 的 rpm 包下载到当前目录,注意,它只下载、不安装。下载完成后可以看到类似tree-1.7.0-10.el7.x86_64.rpm的文件,把这个文件拷贝到内网机器上,执行本地安装。
rpm -ivh tree-1.7.0-10.el7.x86_64.rpmrpm -ivh的i是 install,v是显示详细过程,h是打印进度条。如果这台机器的 CentOS 版本与包来源机器完全一致,这个 rpm 包通常能直接装上。万一提示依赖缺失,比如需要某个libc.so的特定版本,那就需要回到来源机器上把依赖包也一并下载下来,再按顺序安装。这一步之所以容易翻车,就是因为很多人只拷了 tree 一个包,忽略了它的动态链接库依赖。
3.2 源码编译:从 tar.gz 到 make install 全流程
如果连匹配的 rpm 包都找不到,或者你用的是 Arch、Alpine 这类特殊发行版,那就只能走源码编译了。tree 的源码是一个单独的 C 语言源文件加一个 Makefile,编译过程极简,但有几个关键细节值得注意。先把源码包解压:
tar -zxvf tree-2.1.0.tgz cd tree-2.1.0tar -zxvf中,z表示 gzip 压缩格式,x是解压,v显示解压列表,f指定文件名。解压后进入源码目录,你会看到tree.c、Makefile、man目录等。接下来直接编译:
make这个命令会调用 Makefile 里的默认目标,编译出 tree 可执行文件。编译过程如果报错,绝大多数原因集中在缺少 gcc 编译器或缺少libc6-dev这类基础开发库。在 Ubuntu 上可以先补装:
sudo apt install build-essential安装完后重新make,一般就能通过。编译成功后,当前目录下会多出一个名为tree的可执行文件,可以直接用./tree运行。但为了让系统全局都能调用它,还需要执行安装步骤:
sudo make installmake install会把编译好的二进制文件复制到系统目录,通常是/usr/local/bin/tree,同时把 man 文档安装到对应位置。到这里,源码编译的安装流程就走完了。
3.3 源码编译的坑:PATH 路径与旧版本残留
源码编译这种安装方式,最典型也最坑的一个问题就是:make install装到/usr/local/bin,而系统自带的 tree 如果在/usr/bin,两个路径同时在 PATH 里,到底执行了哪个?
这个问题排查起来其实很简单,用which tree就能看到实际调用的路径。如果发现/usr/local/bin/tree排在前面,但你实际想用的是系统自带的版本,可以通过修改~/.bashrc里的 PATH 顺序来调整;反过来,如果编译安装的新版本不生效,多半就是/usr/bin/tree被优先调用了,此时可以用绝对路径/usr/local/bin/tree强制指定,或者把/usr/bin下的旧版本替换掉。
另外还要注意一点:make install默认不覆盖已有的 tree 二进制,如果/usr/local/bin/tree已存在,新编译出来的文件会直接替换它,但旧版本如果是通过 rpm 装的,rpm 数据库里记录的还是旧文件。以后执行yum remove tree时,系统会提示文件被修改或已被替换,这就是「rpm 校验失败」的经典场景,处理办法是rpm -e --noscripts tree强制卸载,或者干脆用--force重新安装覆盖一次。
4. 参数才是重头戏:tree 常用选项的取舍和几种典型输出
4.1 控制层级与隐藏文件的必用参数:-L、-a、-I
tree默认会把当前目录下所有子目录、所有文件从头到尾递归输出,一个/var目录能刷屏几千行。在实际使用里,几乎没有人不限制层级的。最核心的参数就是-L,直接指定递归深度。
tree /var/log -L 2这条命令只显示 /var/log 下的两层结构,第二层以下的文件不再展开。对于只想知道大目录里「有哪些模块」、「哪个子目录最大」的场景,-L 2或-L 3是使用频率最高的组合。
-a参数用来显示隐藏文件,-I则是排除指定文件或目录。很多新手不知道这两个参数要搭配使用:不带-a时,目录下的.git、.env、node_modules里的隐藏文件根本不显示;带上-a后,又会把node_modules这种一眼望不到头的依赖目录全显示出来。所以实际项目里我更推荐组合:
tree -a -I 'node_modules|.git|.DS_Store'-I后面跟的是通配符匹配的文件名模式,用竖线分隔多个匹配项。这里注意,node_modules前面不需要加*/前缀,它匹配的是任意层级下叫这个名字的目录。这个组合对前端项目尤其有用——既能看到隐藏的配置文件,又不会被依赖目录刷屏。
4.2 输出重定向与字符集选择:-o、-C 和乱码根源
tree 的另一个高频场景是把目录结构导出成文本文件,用于写文档或做交付清单。此时要用-o参数:
tree -L 3 -o directory_structure.txt这个命令不会在终端打印任何输出,而是把结果写入directory_structure.txt。写文档时这招相当实用,直接在「文件结构」章节里粘贴这个文件即可。
还有一个容易被忽略的参数是-C,它在输出中为不同类型的文件加上颜色标记——目录、可执行文件、符号链接会显示不同颜色。终端上看没问题,但如果加了-o重定向到文件,颜色转义序列会被写进文本里,打开文件时满屏\033[01;34m之类的乱码字符。
解决思路很简单:重定向输出时强制关闭颜色,不必带-C就行。如果你既想要颜色,又希望终端和重定向两者兼得,可以这样处理:
tree -C | cat当 tree 的 stdout 不是 TTY 时,它通常会默认关闭颜色,但管道场景下部分版本反而会保留,这里加cat是多余动作。更可靠的做法是分离操作:交互式查看用tree -C,写文档用tree -o,两条命令各干各的,不要在一条命令里把两者混在一起。
4.3 以目录为主的输出与文件排序
有些时候你只想看目录结构,不关心文件,比如梳理一个开源项目的模块划分。tree -d就是干这个的,它只显示目录节点。
tree -d -L 2输出效果就是一张纯净的目录骨架图,没有零散文件干扰视线。配合-L 2用,适合快速了解项目的顶层模块划分。
如果需要对输出内容排序,tree 默认按字母序排列,但可以通过--dirsfirst让目录排在文件前面:
tree --dirsfirst -L 2这在看源代码项目时很有用,先看到 src、tests、docs 这些目录,再看到 README、package.json 等文件,整体顺序感强很多。这里补充一个细节:tree的参数顺序不影响结果,但--dirsfirst在使用某些语系环境时可能与-L的解析顺序出现怪问题,所以建议把--开头的长参数写在最后面,这是我在自动化脚本里总结出的习惯。
4.4 输出到 HTML:基于 tree 的交付物扩展
如果你的交付对象是甲方或者非技术同事,光给 txt 文件不一定直观,这时可以试试 tree 的 HTML 导出功能。部分版本的 tree 编译时带上了--output和-H参数,可以生成一个带链接的 HTML 目录页面。
tree -H -L 2 --nolinks -o tree.html-H表示生成 HTML 格式,-L 2限制层级,--nolinks是取消可点击链接(纯展示),-o指定输出文件。生成的 HTML 可以被浏览器直接打开,每层目录折叠展开,体验接近一个小型文档站。不过要提醒的是,-H生成的 HTML 里会嵌入基本样式,但排版很朴素,适合内部资料归档,不适合直接交付给客户做 UI 展示。
5. Linux 下 tree 的避坑与常见问题:乱码、缺失、权限和别名
5.1 中文目录名在 tree 下显示乱码或问号
现象:目录结构能输出,但中文文件名全部变成??????或者一堆无法识别的转义字符,-L深度越大越明显。
原因:tree 默认把文件当作当前 locale 编码来输出。如果系统 locale 是POSIX或C,它就没有 UTF-8 编码的概念,遇到中文直接按字节逐个转成不可打印字符。还有一种情况是 SSH 客户端用了非 UTF-8 编码,比如在 SecureCRT 里选了 GBK,这也会导致乱码。
解决:先确认系统 locale,执行locale,如果输出是LC_ALL=或者LANG=为空说明 locale 没配置。临时解法是直接设置环境变量再跑 tree:
export LANG=en_US.UTF-8 tree一劳永逸的做法是把export LANG=en_US.UTF-8写进/etc/profile或用户~/.bashrc。如果问题只出现在某个远程终端,就去终端设置里把字符集改成 UTF-8,而不是在服务器端纠结。
5.2 某些目录输出 Permission denied
现象:tree /或tree /etc时,命令能执行,但中间夹着一堆Permission denied的报错,目录结构不完整。
原因:tree 以当前用户权限遍历文件系统,遇到没有读权限的目录,会如实报错并跳过。这在排查系统级目录时特别常见,不是 tree 本身坏了。
解决:如果确实需要看完整结构,最直接的方式是用 sudo 提权:
sudo tree / -L 2但要注意,sudo 会改变 locale 环境变量,如果之前设置了 UTF-8 而 sudo 没有保留该变量,输出又可能变成乱码。这一点属于线上环境里常见的连锁坑:权限解决了、乱码又回来了。建议配合sudo -E保留环境变量,或者在使用 sudo 时显式带上LANG=en_US.UTF-8。
sudo -E tree /etc -L 25.3 系统自带别名导致 tree 输出行数异常
现象:在大型仓库里执行tree,文件极多但看不到分页效果,终端疯狂刷屏;或者明明只执行tree,却莫名多出了某些额外的列。
原因:部分系统或用户配置里存在alias tree='tree -a -L 3'之类的别名,这些配置可能来自公司统一运维脚本或自己曾经的实验残留。别名会在不知不觉中改变 tree 的默认行为。
解决:先检查别名定义,执行alias tree,如果输出了内容说明确实定义过。临时绕开别名的方式是\tree,命令名前加反斜杠;彻底修改的办法是编辑~/.bashrc和~/.bash_profile,定位到alias tree=那一行直接删掉或注释,然后source ~/.bashrc生效。这个坑最隐蔽之处在于:报错信息完全看不到,纯粹是行为差异,排查时要靠type tree来区分是外部命令还是 shell 内置的别名。
5.4 tree 命令缺失但周边工具还在:最小化系统的连环坑
现象:内网环境里已经通过 rpm 装好了 tree,但用rsync或scp从别的机器同步文件时,发现对方执行tree /opt依然报command not found。
原因:每台机器的 PATH 环境变量是不同的。通过非交互式 SSH 登录时,~/.bashrc里定义的 PATH 不会加载,所以哪怕 tree 真的装在/usr/local/bin里,用 SSH 远程执行时也找不到命令。
解决:远程执行时显式指定绝对路径,或者把 tree 的路径添加到 SSH 服务端的全局 PATH。通常做法是修改/etc/profile里的 PATH 定义,或者直接/usr/local/bin/tree /opt这样调用。这个坑非常重要,因为它解释了「明明装了,但自动化脚本里还是找不到命令」的问题,本质不是 tree 没装,而是会话初始化时没有把该路径加进环境变量。
6. 把 tree 用出进阶技巧:与 find/grep 配合做目录审计与交付
6.1 结合 find 统计目录占用:tree 输出与 du 对比验证
tree 擅长展示结构,但它的-s和-h参数显示文件大小只是单文件信息,看「哪个目录占空间大」并不直观。更合理的思路是先用 tree 搭出框架,再用du或find去补齐数值细节。
tree -d -L 2 du -h --max-depth=2 --exclude=proc /var 2>/dev/null | sort -rh | head -20第一条命令给目录骨架,第二条命令统计 /var 下各层目录的实际占用,sort -rh按人类可读数字从大到小排序,head -20只看前 20 个产出大户。两相配合,你能很清楚地知道「哪个子目录值得进树里去看」以及「那个目录下面到底堆积了什么文件」。这种组合方式远比单独用 tree 或单独用 du 能解决更多实际问题。
6.2 把 tree 输出变成交付清单:排除干扰项与生成快照对比
在项目交付或变更前,记录当前目录结构快照是一个值得养成的习惯。tree 的输出可以作为当时的快照存档,等几周后再生成一份新的,把两份做 diff,就能直观地看到增删了哪些文件和目录。
tree -a -I 'node_modules|.git|dist|__pycache__' -o /tmp/before.txt # 若干天后 tree -a -I 'node_modules|.git|dist|__pycache__' -o /tmp/after.txt diff -u /tmp/before.txt /tmp/after.txtdiff -u输出的是带上下文差异的格式,新文件、被删除的文件一目了然。这套操作很适合用在发布前确认构建产物没有意外变更、或者审计某个备份目录有没有被外部悄悄写入的场景。我经历过一次线上事故,就是靠这份 tree 快照 diff 找到了一条意外多出来的可疑路径——当时备份脚本和清理脚本共用同一份目录,最后是谁动了文件,靠 diff 才得以确认。
6.3 自定义 tree 的默认参数:为不同环境配置默认行为
如果你实在忍不了每次都要敲-L 2 -I node_modules,可以在~/.bashrc里定义 tree 的别名:
alias tree='tree -L 2 -I "node_modules|.git" --dirsfirst'这样一来,日常交互式会话里敲tree就能得到相对克制的输出。但在写脚本的时候,我反而建议刻意取消别名,用\tree或绝对路径调用原始命令,避免脚本读到异常的默认参数。毕竟自动化和交互是两种心智模式:交互要省事,脚本要确定。
这个习惯也延伸到了我对待第三方工具的态度上:交互环境里尽可能配到顺手,脚本里尽可能回到默认值。今天为了省事加的别名,明天可能就是自动化脚本里最难排查的一处隐性翻车点。希望这篇里记录的安装路径、参数取舍和踩坑细节能帮你少走几步弯路,真正需要它的时候,一条命令就能把目录结构捉拿到自己的屏幕上。
本文还有配套的精品资源,点击获取