ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux查看命令详解:从ls到find,掌握文件与目录的高效查看技巧

Linux查看命令详解:从ls到find,掌握文件与目录的高效查看技巧 很多朋友学 Linux都是从ls、cd、cat这几个命令开始的但真到了日常干活的时候会发现“查看目录和文件”这六个字背后的水很深。同样是看日志有人一条tail -f边写边看有人直接cat把终端刷到卡死同样是查磁盘占用有人翻半天找不到大头在哪有人一条du -sh就锁定了元凶。这篇东西不打算把 Linux 命令大全搬过来而是聚焦到 shell 里最高频的“查看”场景把ls、cat、less、tail、find、du这些命令讲透顺带把新手最容易踩的坑也扒一遍。适合刚接触 Linux 的初学者也适合那些用了一段时间、但总觉得自己命令学得太散的朋友。1.ls命令不只是“列出文件名”这么简单1.1 从裸ls到ls -l中间差了哪些信息ls是 Linux 里使用频率最高的命令没有之一。但很多教程只告诉你“ls列目录ls -l列详细信息”然后就没了。实际上ls -l输出里每一列都是有用信息看不懂这些后面排查问题会非常吃力。一个典型的ls -l输出长这样$ ls -l /etc/profile -rw-r--r-- 1 root root 807 4月 15 2023 /etc/profile逐列拆解第一列-rw-r--r--第一个字符是文件类型-代表普通文件d目录l软链接b块设备c字符设备。后面 9 个字符是权限位分三组属主owner、属组group、其他用户other每组按r读、w写、x执行排列。第二列1硬链接数。普通文件默认为 1目录的硬链接数至少是 2.和父目录里的条目。第三列root文件的属主。第四列root文件的属组。第五列807文件逻辑大小单位是字节。第六列4月 15 2023最后修改时间。第七列/etc/profile文件名本身。有一个地方特别容易误导新手ls -l显示目录时大小通常是一个固定值比如4096。这是目录这个“文件”本身的元数据占用的磁盘块大小和目录里所有文件的总大小没有任何关系。要查看目录内容的总占用得用后面要讲的du。1.2 高频参数组合为什么大家偏爱ll ls -l很多发行版默认在~/.bashrc里配置了alias llls -l所以大家习惯用ll。但如果你在脚本里写ll到别的机器上大概率会报command not found——这就是别名的坑后面单独说。实际工作中最常用的几个组合命令效果典型场景ls按列列出文件名快速扫一眼目录里有什么ls -l/ll长格式包含权限、属主、大小、时间查看文件属性、确认权限ls -a显示隐藏文件以.开头的文件查看.bashrc、.ssh等配置文件ls -lh长格式大小以 K/M/G 显示人眼友好的方式查看文件大小ls -lt按修改时间倒序排列看最新改动的文件ls -lrt按修改时间正序排列最新文件在末尾日志目录里查看最新日志ls -ld显示目录本身的信息而不是目录内容检查目录权限、属主时很有用举几个实际场景看某个目录的权限时ls -l /home列出的是/home里面所有子目录的权限而ls -ld /home才是/home自身的权限。这个“目录底下所有条目”和“目录自己”的区别新手经常搞混。查日志时ls -lrt /var/log/把最老的文件排前面、最新的排最后配合终端往下翻一行就能看到今天新产生的日志文件比ls -l默认的排序方式好用得多。1.3 通配符的真相ls *.log里的*是 shell 展开的很多新手以为ls支持正则表达式于是兴冲冲地写了ls ^file结果报错。这里必须先澄清ls *.log里的*不是ls的功能而是 shell也就是 bash在启动ls之前先把*.log展开成当前目录下所有以.log结尾的文件名然后ls收到的其实是一串具体的文件名。这个区别很重要因为它带来一个经典报错$ ls *.log ls: cannot access *.log: No such file or directory当前目录一个.log文件都没有时bash 默认把*.log原样传给lsls找不到这个名字的文件就报错了。如果是在脚本里遇到这个报错说明路径不对、文件确实不存在或者当前工作目录和你以为的不一样。这个“我以为在 A 目录实际在 B 目录”的问题是新手排错时最大的障碍后面会讲到怎么用命令确认当前路径。顺便说一句ls的通配符和find的-name参数也不要混淆。find -name *.log这里的*是find自己解析的不是 shell 展开的所以即使一个文件都没有find也只是无结果返回不会报错。2. 查看文件内容的命令家族cat、more、less、head、tail怎么分工2.1cat的用途和代价拼接、创建以及为什么会刷爆终端cat的名字来自 concatenate拼接它最基本的用途是把文件内容输出到标准输出另一个用途是拼接多个文件# 把 a.txt 和 b.txt 按顺序拼成 c.txt cat a.txt b.txt c.txt # 查看文件并显示行号 cat -n /etc/hostnamecat -n显示行号确实方便但有个隐患处理包含制表符、特殊字符的文件时肉眼很难分辨空格和 Tab。这时候可以上cat -A它会把行尾标记成$把 Tab 显示成^I。后面讲“Windows 换行符导致脚本报错”的排查时cat -A是神器。还有一个很实用但经常被忽略的技巧用cat创建文件。$ cat notes.txt hello world 按 CtrlD 结束输入这种方式比vim轻量适合快速记几行内容。但要注意是覆盖写才是追加写。如果第二次执行cat notes.txt之前的内容会被清空。这个“覆盖、追加”的规则在会写 shell 脚本之前请务必刻进脑子里。cat最大的问题是它一次性把所有内容全部输出。文件几 GB 时终端会被刷到几乎没法看甚至卡死。所以查看大文件要换下面的命令。2.2more与less翻页查看的正确打开方式less的说明文档自己都写着 “less is more”——意为less比more强。more只能往下翻页往回翻在很多实现里是做不到的less支持上下方向键逐行滚动、PageUp/PageDown翻页、/关键字搜索、n跳到下一个匹配项、g跳转第一行、G跳转最后一行最后按q退出。查看配置文件、源代码、日志文件我几乎只用less不用more。原因很简单大文件不会一次性加载进内存less是按需读取的打开 2GB 的日志文件也没压力。这一点上和cat有本质区别。2.3head与tail只看头部和尾部以及tail -f看日志的爽点head和tail默认只显示 10 行用-n指定行数# 看前 20 行 head -n 20 /etc/passwd # 看后 50 行 tail -n 50 /var/log/syslog真正的杀招是tail -f-f是 follow 的意思它会持续跟踪文件尾部文件有新内容写入时自动刷新出来。排查系统日志、应用日志时开一个终端挂着tail -f /var/log/nginx/access.log然后去浏览器里刷新页面日志立刻滚动更新那种“实时看见请求进来”的爽感用过一次就回不去了。tail -f在日志轮转logrotate场景下有个需要注意的点-f跟踪的是文件 inode如果日志被 rename 成access.log.1并新建了空的access.logtail -f还会盯着旧的access.log.1看起来像“卡住了”。这时候用tail -F大写它会在发现原文件被替换后自动重新打开同名文件。生产环境排查日志建议直接tail -F。这四个命令适合的场景差异用一个表总结命令适合场景不适合场景cat短文件、拼接、创建文件大文件会刷屏卡顿more只需往下翻页需要回看前文less翻页查看、搜索、浏览大文件只需看最后几行时略麻烦head只看文件开头部分文件内容大部分在尾部时tail -f/-F实时跟踪日志需要看历史全部内容时3. 从“看到”到“找到”目录树、磁盘占用与文件定位3.1tree查看目录树层级结构一目了然ls只能展示一层当目录嵌套很深时肉眼一层层cd进去太慢了。tree命令可以直接画出整棵目录树# 限制两层深度只看目录不显示文件 tree -L 2 -d /var # 带文件大小显示 tree -h /opt/myapp不过要留意很多发行版默认没有安装treeDebian/Ubuntu 系用apt install treeCentOS/RHEL 系用yum install tree。它算“锦上添花”的工具没装的时候用find也能达到类似效果只是呈现方式不如tree直观。3.2du和df磁盘空间到底去哪了“服务器磁盘满了”是运维里最经典的告警之一排查这个问题的第一板斧就是du。# 看当前目录下每个子目录占了多少空间 du -h --max-depth1 # 看指定目录总占用 du -sh /var/log # 列出所有文件/目录并按大小排序 du -ah /var | sort -rh | head -20du -sh /var/log里的-s是 summarize汇总只显示合计-h是 human-readable人类可读输出 K/M/G 单位。--max-depth1控制列出多少层子目录这个参数在目录结构很深的场景下非常有用。du统计的是“文件实际占用的磁盘块”和ls -l显示的逻辑文件大小不一定一致。稀疏文件sparse file就是典型例子一个文件逻辑上 10GB但里面全是空洞实际占用的磁盘空间几乎为 0。用ls -l看是 10G用du -h看可能只有 4K。如果你怀疑磁盘空间被莫名占掉一定要以du为准不要以ls为准。df负责的是另一个维度它看的是文件系统分区级别的空间df -h输出里会看到/dev/vda1之类的分区挂载在/下使用率多少、剩余多少一目了然。du帮你定位“是哪个目录占了空间”df帮你看“整个磁盘还剩多少”两者配合才能完成完整的排障链路。3.3find按名字、类型、大小、时间定位文件find是我心目中 Linux 上最值得反复练习的命令之一。它和ls最大的区别是ls先列出来再靠人眼翻find直接按条件筛选。最常用的几个条件# 找当前目录下所有 .log 文件 find . -name *.log # 忽略大小写找 .LOG 文件 find . -iname *.log # 找所有目录不包含文件 find /etc -type d # 找所有软链接 find /usr/bin -type l # 找大于 100MB 的文件 find /data -type f -size 100M # 找 7 天内修改过的文件 find /data -type f -mtime -7-mtime是修改时间-mtime -7表示 7 天以内-mtime 30表示 30 天以前。排查日志清理策略时这个参数是主力。find配合-exec可以批量操作但这里有一个新手必踩的坑文件名里有空格时直接find . -name *.log | xargs rm会炸因为空格会把一个文件名切分成多个参数。正确的姿势是用-print0配合xargs -0find . -name *.log -print0 | xargs -0 rm-print0用空字符分隔文件名xargs -0也按空字符解析这样就算文件名里有空格甚至换行符也不会出错。这个技巧在脚本里处理批量删除、批量移动时非常关键。3.4locate、which、type另一个维度的“找”find是实时遍历磁盘性能相对慢locate是查预建的数据库秒出结果locate nginx.conf但locate依赖updatedb定期更新数据库刚创建的文件查不到而且很多发行版默认没装。所以更通用的建议是正经定位文件用find想快速找“某个软件装的配置在哪”可以用locate前提是接受它的延迟。which和type是找“命令本身在哪”的$ which python3 /usr/bin/python3 $ type -a ls ls is aliased to ls --colorauto ls is /usr/bin/lstype -a会列出同名的 alias 和外部命令排查“为什么我写的命令和预期行为不一样”时很管用。4. 文件类型、路径与ls -l输出里的隐藏信息4.1 别再靠扩展名猜文件类型了用fileWindows 用户刚接触 Linux 时喜欢盯着扩展名.exe是程序、.txt是文本。Linux 不这么玩它靠文件内容来识别类型$ file /etc/passwd /etc/passwd: ASCII text $ file /bin/ls /bin/ls: ELF 64-bit LSB executable, x86-64, dynamically linked ...file读文件头部特征魔数判断类型不管文件名是什么。所以你会看到$ file backup.tar.gz backup.tar.gz: gzip compressed data它直接告诉你tar.gz本质上是 gzip 压缩的数据。碰到不认识的文件、或者在 Windows 和 Linux 之间来回传输的文件先file一下能省掉很多瞎猜的时间。4.2 路径表示的坑.、..、~、-分别代表什么路径看似简单却是无数新手挂掉的第一站。.当前目录..上一级目录~当前用户的家目录~user指定用户的家目录比如~root就是/root-上一次所在目录cd -这个用法特别实用在 A 目录和 B 目录之间反复切换时不用把完整路径再敲一遍。绝对路径和相对路径要分清绝对路径从/开始相对路径从当前目录开始。写脚本时建议优先用绝对路径因为脚本执行时的工作目录不一定是你以为的那个。一个典型场景cron 定时任务里执行脚本脚本里写的是logs/xxx.log但 cron 的工作目录不是脚本所在目录结果就是“脚本明明运行了日志却不见了”。这就是相对路径的锅。4.3ls -i与statinode、硬链接和时间戳的正确解读ls -i可以查看文件的 inode 编号$ ls -i /etc/hosts 786866 /etc/hostsinode 是文件在文件系统里的身份证。两个文件名如果 inode 一样它们其实是同一个文件的两个名字这就是硬链接的本质。判断方式很简单$ ln /tmp/foo /tmp/bar $ ls -li /tmp/foo /tmp/bar 393233 -rw-r--r-- 2 root root 0 ... 393233 -rw-r--r-- 2 root root 0 ...两个名字的 inode 都是393233硬链接数从 1 变成 2。硬链接的好处是删除其中一个文件名文件内容不会丢只要还有一个名字指向这个 inode。软链接符号链接则完全不同它是独立的文件inode 不同内容里保存的是目标路径$ ln -s /tmp/foo /tmp/foo_link $ ls -l /tmp/foo_link lrwxrwxrwx 1 root root 8 ... /tmp/foo_link - /tmp/foo第一列是l箭头指向目标。软链接可以跨文件系统可以指向目录但目标被删除后它就变成了“死链”dangling访问时会提示No such file or directory。想一次看全文件的所有元数据用stat$ stat /etc/hostname File: /etc/hostname Size: 10 Blocks: 8 IO Block: 4096 regular file Device: fd00h/64768d Inode: 393236 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2024-01-01 00:00:00 Modify: 2023-12-20 10:30:00 Change: 2023-12-20 10:30:00 Birth: 2023-12-20 10:30:00stat输出里最容易被误解的是时间戳Access最近一次读取时间执行cat会更新它。Modify内容修改时间vim改过文件内容就会更新。Changeinode 状态变化时间chmod、chown、硬链接数变化都会更新它即使内容没变。Change不是“创建时间”这是面试和实际排障中非常高频的一个误区。比如你用chmod x给脚本加了执行权限后Modify没变Change变了。如果有人在排查“文件什么时候被改的”时盯着Change看很容易误判。5. 组合起来用搜索内容、管道协作、批量处理与 shell 脚本基础5.1grep内容搜索里最强的“查看”手段前面讲的都是“查看文件”但现实中更常见的需求是“查看文件里的某一部分”。总不能打开一个几千行的日志慢慢翻这时候grep就是主力# 查看包含 ERROR 的行 grep ERROR app.log # 忽略大小写 显示行号 grep -in error app.log # 递归搜索某个目录下的所有文件 grep -r timeout /etc/nginx/ # 只列出包含关键字的文件名不显示具体内容 grep -l timeout /etc/nginx/*.conf # 统计匹配行数 grep -c timeout app.loggrep -r可以查找“关键字出现在哪个文件”配合-l只输出文件名排查配置项时特别高效。比如你改了 Nginx 配置但不确定有没有生效直接grep -r worker_processes /etc/nginx/所有配置文件里涉及这个指令的位置全部列出来不用一个个打开文件找。5.2 管道把多个命令串成一条流水线管道符号|把前一个命令的输出交给后一个命令继续处理。这是 shell 里最强大的协作机制也是“组合拳”的基础# 只看目录不看文件 ls -l / | grep ^d # 统计当前目录下文件个数 ls -l | grep ^- | wc -l # 查看某个进程是否在跑 ps aux | grep nginx管道从右往左看先执行ps aux把输出交给grep nginx只留下包含nginx的行。排查进程、排查端口、统计日志几乎事事离不开管道。grep -v表示反向匹配排除掉某些行。比如想看日志里除了INFO之外的所有内容grep -v INFO app.log5.3${}和$()变量替换与命令替换到底是两码事这是我见过初学者问得最多的问题之一${}和$()看着像亲兄弟作用完全不同。${}是变量替换取变量的值nameworld echo Hello, ${name} # 输出 Hello, world$()是命令替换执行里面的命令并把输出结果作为值返回echo 今天日期是 $(date %F) # 输出 今天日期是 2024-01-15一个典型的组合场景脚本里需要把某个命令的结果存进变量再使用log_file$(find /var/log -name *.log -mtime -1) echo $log_file${}和$()可以同时出现在一行命令里各管各的echo 当前用户 ${USER} 的 home 目录下有 $(ls -l ~ | wc -l) 个条目注意$()里的命令会先执行完把结果拼接到外层命令里然后再执行外层命令。这和管道“逐个处理”的思路不同但效果上都是把子命令的输出利用起来。5.4for循环与批量重命名shell 脚本处理的起点热词里出现了“shell for 循环”在查看目录和文件的场景里它同样重要——找到一堆文件之后真正的价值往往在于批量处理它们。最经典的批量重命名# 把所有 .txt 文件改名为 .bak for f in *.txt; do mv $f ${f%.txt}.bak done这里${f%.txt}是变量替换的一种表示“从字符串末尾去掉.txt这段”然后拼上.bak。所以a.txt变成a.bak。find配合for可以处理更深层目录的文件# 找到 /data 下所有 .log 文件逐个压缩 for f in $(find /data -name *.log); do gzip $f done但这里有个隐患$(find ...)会把结果按空格拆分成多个词文件名里有空格就会出问题。更稳妥的做法是用while循环配合find -print0find /data -name *.log -print0 | while IFS read -r -d f; do gzip $f done这个写法看着复杂但它正确处理了所有特殊字符。在正式脚本里我强烈建议用这种“防呆”写法别为了省几行代码给线上脚本埋雷。脚本里还有一个常被问到的shift命令它的作用是左移位置参数$2变成$1$3变成$2。写命令行工具时用来逐个吃掉参数非常方便while [ $# -gt 0 ]; do echo 处理参数: $1 shift done5.5 脚本执行的权限坑为什么有时候明明在目录里脚本却跑不起来写完一个test.sh兴冲冲执行./test.sh结果报Permission denied。这不是脚本内容的问题而是文件没有执行权限。两种解决方式# 方式一加执行权限 chmod x test.sh ./test.sh # 方式二用解释器直接跑不需要执行权限 bash test.shbash test.sh的本质是bash这个程序去读test.sh的内容并执行所以test.sh本身不需要 x 权限。而./test.sh是内核按可执行文件处理必须检查 x 权限。如果脚本开头写了#!/bin/bashshebang执行./test.sh时系统会找到/bin/bash来解析这个脚本如果没写默认用当前 shell 解析容易出兼容性问题。所以写脚本第一行固定写#!/bin/bash是每个 Linux 用户都应该养成的习惯。6. 高频踩坑与自查清单权限、别名、编码和面试考点6.1 权限的嵌套陷阱我不能查看这个目录但我能直接访问里面的文件先记住权限模型目录的r决定你能不能列出目录里的文件名x决定你能不能“穿过”这个目录访问里面的文件。一个典型的场景$ ls /root ls: cannot open directory /root: Permission denied这是没有r权限。但如果你知道目录里有一个文件名比如/root/secret.txt然后$ cat /root/secret.txt hello也能成功。原因是你对/root有x权限但没有r权限这导致你不能“列目录”但可以“访问指定名字的文件”。有些朋友碰到ls报权限错就以为整个目录都不能碰其实不是要用ls以外的思路试试。还有一个容易看错的地方ls能列出文件名不代表你能读文件内容。列表需要目录的r读内容需要文件自己的r。排查“为什么我能 ls 却不能 cat”时先ls -l看这个文件的权限再ls -ld看父目录的权限两级权限分开查。6.2 别名的坑为什么ll在这个机器上有在另一个机器上就没了ll在很多 Ubuntu 发行版上是默认配置好的别名指向ls -alF之类的组合。但到了最小化安装的 CentOS 或容器镜像里可能没有ll。原因很简单ll根本不是系统命令它是某个用户在自己环境里定义的别名。想查当前 shell 里有哪些别名alias想临时取消某个别名unalias ll想让别名永久生效要写进~/.bashrcecho alias llls -l --colorauto ~/.bashrc source ~/.bashrc另一个更隐蔽的坑是非交互式 shell比如执行 shell 脚本时默认不加载~/.bashrc也就不会展开别名。所以你在脚本里写ll十有八九会失败。脚本里老老实实用ls -l别用别名。6.3 解压 ZIP 后文件名乱码根源是编码不是命令错Windows 上压缩的 ZIP 文件文件名默认用本地编码中文环境通常是 GBK/CP936而 Linux 默认用 UTF-8 解压于是中文文件名全部变成乱码。热词里专门有“linux 解压文件乱码”这个坑太经典了。解决方式取决于用的工具。用unzipunzip -O CP936 文件.zip-O指定解压时使用的编码字符集。如果系统unzip版本不支持-O有些发行版编译时没开启可以装unarapt install unar unar 文件.zipunar会自动检测编码基本能一把解出来。解压出来的文件如果还有乱码文件名用ls倒是能看到但要重命名处理就比较麻烦可以用convmvconvmv -f GBK -t UTF-8 --notest -r 目录/这个命令会把目录下所有文件名从 GBK 转成 UTF-8。6.4 经典排查案例Windows 上写的脚本到 Linux 上报错这个案例几乎每个团队都会遇到。Windows 文本文件的换行符是\r\nLinux 只认识\n。于是你在 Windows 上写了一个test.sh传到 Linux 上执行报各种莫名其妙的错比如\r: command not found。排查的第一板斧就是cat -A$ cat -A test.sh | head -5 #!/bin/bash^M$ echo hello^M$行尾的^M就是\r。确认之后处理方式有两种# 用 sed 去掉所有行尾的 \r sed -i s/\r$// test.sh # 或者安装 dos2unix dos2unix test.sh这个案例说明一个道理看文件内容时不要只相信肉眼看到的“字符”cat -A这类能显示隐藏字符的命令才是排查文本问题的最终底牌。执行file test.sh也能看出端倪——如果输出里出现 “with CRLF line terminators”说明换行符问题坐实了。6.5 面试和笔试里关于“查看”的典型考点热词里出现“linux面试题测试”我就把与本文相关的考点整理一下。大部分面试官问“查看目录和文件”不是单纯考命令拼写而是考你对输出信息的理解。考点常见问法关键要点ls -l权限列请解释-rwxr-xr--的含义文件类型 三组权限缺一不可软链接和硬链接两者区别ln 和 ln -s 分别创建什么硬链接共享 inode软链接是独立文件目录不能做硬链接find与grep两者都带“搜索”字样区别是什么find搜文件名和文件属性grep搜文件内容查看大文件一个文件有几个 GB用什么命令less不用cat实时日志怎么实时查看不断追加的日志tail -f或tail -F并说明日志轮转场景的坑隐藏文件怎么查看所有文件包括隐藏的ls -a磁盘占用磁盘满了怎么定位大目录du -sh *、du -h --max-depth1区分du与df时间戳stat里的 Modify 和 Change 有什么区别内容 vs inode 状态chmod改变的是 Change面试官问这些问题的潜台词其实是你真的在命令行里干过活吗还是只背了命令列表考前把上面这些场景亲手在终端敲一遍比背 100 条命令管用得多。再补充一个我自己的习惯面对一台陌生机器我的第一轮侦察永远是这几条pwd # 我在哪 ls -la # 这里有什么 df -h # 磁盘剩多少 du -sh * 2/dev/null # 谁占的空间最大 find . -maxdepth 2 -mtime -1 -type f # 最近改了什么这一整套打下来不管服务器是从别人手里交接的还是新装的系统我对它的“家底”基本心里有数。新手可以把这个当成固定套路练一练练熟了就不用每次面对一台新机器都心里发慌了。Linux 的命令数量多如牛毛但真正每天在用的核心其实就那几十条把“查看目录和文件”这一块玩透后面的学习会顺很多。
返回列表