basename、dirname、tree本节摘要:本章的收尾节,讲三个「小而美」的工具。
basename和dirname负责把一个完整路径拆成「文件名」和「目录部分」——这俩在 Shell 脚本里几乎天天用(比如从/a/b/c.txt取出c.txt或/a/b)。tree则把目录结构画成树形,是调试与文档的利器。它们单独看都简单,但理解它们的用法,能让你在写脚本时少走很多弯路。本节也会顺带把本章「文件与目录」的知识做一个简短回顾,为下一章「文本处理」做衔接。
内容来源:原项目「Linux 命令大全」
command/basename.md、command/dirname.md、command/tree.md,精选并套用体系化模板。
阅读完本节,你应当能够:
basename 从完整路径取出文件名部分,并能去掉指定扩展名。dirname 从完整路径取出目录部分。tree 以树形可视化目录结构,掌握 -L(深度)、-a(含隐藏)、-d(只看目录)、-h(带大小)等选项。basename/dirname/tree 解决脚本里的路径处理需求。写 Shell 脚本时,你常会拿到一个完整路径(比如遍历文件得到的 /data/logs/app.log),却只想要其中一部分:有时要文件名(app.log),有时要目录(/data/logs),有时要不带扩展名的名字(app)。如果靠 awk -F'/' 或 sed 去拆,既啰嗦又易错。
basename 和 dirname 就是为这个需求设计的专用工具——它们正确处理路径的各种边界情况(尾随斜杠、多层目录、空扩展名),让你一行搞定。它们的本质是对路径字符串做「按最后一个斜杠切分」:
路径: /data/logs/app.log ↑ 最后一个斜杠 dirname 部分: /data/logs (斜杠左边) basename 部分: app.log (斜杠右边)
basename /a/b/c.txt # 输出 c.txt basename /a/b/c.txt .txt # 输出 c (去掉指定后缀) basename /a/b/c.txt .log # 输出 c.txt (后缀不匹配, 原样输出) basename /a/b/ # 输出 b (尾随斜杠被忽略)
dirname /a/b/c.txt # 输出 /a/b dirname /a/b/ # 输出 /a (尾随斜杠被忽略, 取倒数第二级) dirname c.txt # 输出 . (没有目录部分时给当前目录)
# 批量给 .txt 文件加 .bak 后缀 for f in *.txt; do name=$(basename "$f" .txt) # 去掉 .txt, 得到纯名字 cp "$f" "${name}.txt.bak" # 拼出备份文件名 done # 从完整路径得到"父目录 + 新文件名" path=/data/logs/app.log dir=$(dirname "$path") # /data/logs newname=$(basename "$path" .log).csv # app.csv echo "$dir/$newname" # /data/logs/app.csv
tree # 当前目录的树形结构 tree -L 2 # 只看 2 层深度(大目录必备) tree -d # 只看目录, 不显示文件 tree -a # 含隐藏文件(点开头) tree -h # 带文件大小 tree -L 2 -d --dirsfirst # 目录优先排前
示例输出:
$ tree -L 2 . ├── docs │ ├── guide.md │ └── api.md ├── src │ ├── main.py │ └── utils.py └── README.md
💡 技巧:
tree默认可能没装(apt install tree或yum install tree)。装上后,它比ls -R的输出直观得多,特别适合在文档里展示项目结构。
basename photo.tar.gz .gz # 输出 photo.tar (只去掉 .gz) basename photo.tar.gz .tar.gz # 输出 photo (去掉 .tar.gz)
basename 的第二个参数不是正则,是字面字符串,只从末尾匹配一次。想去掉多层后缀,要么把完整后缀写全(.tar.gz),要么配合 sed。
dirname "app.log" # 输出 . (当前目录)
这是个合理的「无目录则视为当前目录」的设计,但在脚本里拼接路径时要注意,. /new.log 不是合法路径。用 realpath 或 [ "$dir" = "." ] && dir=$(pwd) 处理。
name=$(basename "/data/my file.txt") # 对, 加引号 name=$(basename /data/my file.txt) # 错! 会被拆成两个参数
路径含空格是 Shell 脚本的头号坑。所有变量化的路径,在用 $var 时都加双引号:cp "$f" "${name}.bak"。
basename 路径 取文件名部分;basename 路径 .后缀 可顺便去掉指定后缀(字面匹配,非正则)。dirname 路径 取目录部分;纯文件名(无斜杠)返回 .(当前目录)。tree 树形可视化目录:-L 限深度、-d 只看目录、-a 含隐藏、-h 带大小;比 ls -R 直观。$var 引用都该加引号。至此第 2 章「文件与目录管理」全部讲完。本章从最朴素的 ls/cd 开始,一路讲到 i 节点与硬软链接——你现在已经能熟练操纵文件树,并理解了「文件是什么」的底层结构。下一章我们把视角从「文件本身」转到「文件里的文本」,进入全书最硬核的文本处理流水线。