Linux基础命令实战指南:从路径权限到日志排查的完整思路
我们经常在各类教程、面试题、项目README里看到“Linux基础命令”这几个字但真正肯花时间把命令背后的逻辑吃透的人并不多。很多人是遇到什么问题复制一条命令跑通了就算完事。可一旦环境变了、权限不够了、目录结构复杂了立刻抓瞎。这篇文章我想换一种讲法不按命令字典的顺序一条条念而是按照“你实际会遇到的运维场景”重新组织一遍把那些高频命令的用法、参数选择的理由、容易踩的坑一次性讲清楚。适合刚接触Linux的开发者、正准备系统学习运维的初学者以及想把手头命令用得更明白的人。说实话Linux命令本身并不难难的是“在哪个场景下选哪条命令、为什么这样选”。我会尽量把每条命令的使用逻辑拆开用我这些年实际踩坑换来的经验去解释而不是简单贴一个参数表。文章最后还整理了一份高频问题速查和实操坑点希望对你有用。1. 动手前先把三个底层概念玩明白很多命令记不住、用不对根子不在命令本身而在三个基础概念没有真正建立起来路径、权限、通配符。这三样东西理解透了后面所有命令都会顺畅很多。1.1 绝对路径与相对路径说得清的“位置感”路径问题是一切命令操作的地基。你在终端里敲的每一个文件参数本质上都是在告诉系统“我要找的东西在哪”。绝对路径是从根目录/开始写的完整路径比如/home/project/logs/app.log它的特点是不管你现在在哪个目录这条路径都指向同一个地方适合在脚本里使用也适合跨目录操作时避免搞错位置。相对路径则是相对于当前所在目录的路径比如当前你在/home/project那么logs/app.log就指向同一个文件。相对路径的好处是输入短、直观缺点是结果依赖“当前位置”很容易因为换了一个目录就失手。判断自己当前在哪用pwd这个命令几乎没有参数就是打印当前工作目录的绝对路径。有个容易被忽略的细节pwd显示的是“逻辑路径”如果你是通过软链接ln -s进入的目录某些环境下它会显示链接本身的路径而不是真实物理路径。想看到真实位置可以加-P参数。这个问题在写自动化脚本时偶尔会坑人一旦脚本里对路径做了字符串拼接逻辑路径和物理路径的差异就会冒出来。cd命令也藏了几个实用细节。cd -可以快速回到上一次所在的目录这个在两边目录来回切换时非常省事。cd ~回到当前用户的家目录但要注意sudo执行命令时家目录仍然是普通用户的家目录除非用了sudo -i。我遇到过不少新手在sudo su之后搞不清自己在哪个目录最后把文件写到奇怪的地方。1.2 权限模型为什么Linux总让你加sudoLinux的权限模型可以用一个简单例子理解一个文件能被谁读、写、执行由三组权限决定分别对应文件所属用户、所属组、其他用户。每组权限用r、w、x三个字母表示对应数字是4、2、1。常见的ls -l输出长这样-rw-r--r-- 1 zhangsan dev 1024 Mar 14 10:00 app.conf拆开看第一个字符-表示普通文件如果是d就是目录l是软链接后面九个字符三位一组rw-是属主权限可读可写不可执行r--是组权限只读r--是其他用户权限只读。这串字符后面跟着的是属主和属组。理解了这套模型你就能明白为什么很多命令要加sudo。比如修改系统级配置文件/etc/nginx/nginx.conf这个文件属主是root普通用户对它的权限通常只有r--根本没有写权限系统才会拒绝你。遇到Permission denied时不要第一时间怀疑命令写错了先看看当前用户对这个路径的权限够不够。目录的权限和文件稍有不同很多人容易混淆目录的r权限让你能列出目录内容w权限让你能在目录里新建或删除文件x权限让你能进入目录。所以要访问/home/a/b/c你对每一层目录都需要x权限缺了哪一层都会报错。这是排查权限问题时最容易疏忽的点。1.3 通配符与引号批量操作的组合拳通配符是Shell里非常实用的批量处理工具。*匹配任意多个字符?匹配单个字符[abc]匹配方括号内的任意一个字符。比如*.log匹配所有以.log结尾的文件access.?匹配access.a、access.b这类单字符扩展名的文件。需要注意通配符是由Shell展开的不是由命令本身处理的。也就是说你敲rm *.logShell会先把*.log展开成当前目录下所有匹配的文件列表再把这一串文件名传给rm。有个致命问题如果当前目录没有任何.log文件Shell可能把*.log原样传给rm于是它试图删除一个真的叫*.log的文件。某些Shell默认配置下会因此报错而不是误删但不同发行版的默认行为不完全一致所以在脚本里最好用nullglob之类的选项做保护或者提前判断匹配结果是否为空。引号的作用则是阻止Shell展开。双引号会阻止通配符展开但保留变量替换单引号什么都阻止。举一个常见场景你想查看文件里包含*符号的行写成grep * file.txt会出问题因为*被Shell展开了写成grep * file.txt才是按字面意思查找星号。这个差异初看很小实际排查问题时能省下不少时间。2. 文件与目录操作每天都要用的那批命令文件操作是整个Linux使用中频率最高的一类但正因为太常用很多细节反而没人讲透。2.1 看位置、列目录pwd与ls的实用细节ls可能是你敲得最多的命令之一但它有不少被低估的用法。最基本的ls只是列出文件名ls -l显示详细信息包括权限、属主、大小、修改时间ls -a显示隐藏文件以点开头的文件ls -h以人类可读的格式显示文件大小比如1K、234M。推荐组合是ls -lah好处是信息全且可读性高。还有一个容易被忽略的参数-t按修改时间排序这对快速找到“最近改动的文件”非常有用。比如要确认某个服务的配置文件是否刚被修改过在/etc/nginx/下执行ls -lt | head -5就很直观。ls的输出还取决于你是否指定目录参数。不带参数时列出当前目录内容带路径时列出指定目录内容。一个实用小技巧ls -l的第五列是文件大小但遇到目录时这个数字并不准它只是目录元数据的大小远远小于目录内文件的总大小。想知道目录里所有文件的总大小得用du -sh这两个命令别弄混了。2.2 新建、复制、移动、删除操作前先想清楚新建目录用mkdir -p-p的含义是“自动创建父目录”比如mkdir -p /tmp/a/b/c会把a、b、c一并建好。没有-p时只要中间某一级目录不存在就报错。写脚本时几乎都带上-p省心很多。新建空文件用touch。很多人只把它当成“创建一个文件”其实它的主要用途是更新文件的修改时间。如果文件不存在touch会顺手创建一个空文件。这个特性在需要快速生成占位文件时很好用比如touch /tmp/flag作为某个脚本执行过一轮的标记。cp复制文件时建议默认带上-a或-r。-r递归复制目录-a除了递归外还会保留文件的权限、属主、时间戳等属性。复制配置文件时用cp -a能最大程度保留原始状态避免因为权限变化导致服务起不来。如果你只想复制目录内容而不包含目录本身可以在源路径后加/比如cp -a /etc/nginx/ /backup/nginx/这个差异需要实际用几次才能体会到。mv移动文件或改名同一个文件系统内就是改名跨文件系统才真正发生复制再删除。如果你的磁盘空间不足跨文件系统mv大文件时可能会失败或者非常慢这也是需要提前了解的。删除命令rm是很多惨案的源头。二进制包里流传着一句话“rm -rf 跑得比谁都快”但这不是用法问题而是安全意识问题。我的习惯是删重要目录前先敲一遍绝对路径让Shell自动补全确认路径无误后再执行可以用ls -d查看一下目录是否存在再继续操作。2.3 批量化处理一段真实整理场景假设一个项目目录里散落着大量日志文件和临时文件想把这些日志统一移动到logs/目录下最简单的做法是mkdir -p logs mv *.log logs/如果只想按日期移动某些文件比如只处理access20250101.log到access20250301.log这类文件可以借助findfind . -maxdepth 1 -name access*.log -exec mv {} logs/ \;这里find的-maxdepth 1限制只在当前目录查找不加会递归到子目录很容易把已经归档的日志又移动一遍。-exec ... {} \;是对每个匹配结果执行一次移动命令。第一次用find -exec的人可能会忘记结尾的分号和花括号的引用方式可以多练习几次。批量删除超过30天的日志文件我常用的是find /var/log/myapp -type f -name *.log -mtime 30 -delete-mtime 30表示修改时间超过30天。先用ls或find不带-delete查看匹配结果确认无误后再加上-delete执行。这个习惯让我避免过好几次误删。3. 内容查看与检索陪你排查问题最多的一类命令日志排查、配置确认、数据提取这些工作都离不开内容查看类命令。它们的选型逻辑很简单文件多大要看多少。3.1 根据场景选查看工具cat、less、head、tailcat最适合查看短小而完整的文件内容。它会一次性把所有内容输出到终端文件一大就刷屏而且终端缓冲有限前面的内容根本看不全。要查看完整文件但文件很长时多用less。less支持上下翻页、搜索按/输入关键词可以高亮匹配结果按n跳到下一个按q退出。我用less的频率比cat高很多尤其在看配置文件或服务启动日志时。head和tail分别查看文件开头和结尾。几乎所有人都会用tail -f来实时跟踪日志比如tail -f /var/log/myapp/error.log这个命令会持续输出新追加的内容非常适合调试服务。有时候日志文件发生轮转比如按天切分tail -f会跟丢文件这时可以用tail -F它会根据文件名重新打开文件即使文件被重建也能继续跟踪是日志轮转场景下的正确选择。查看文件中间某一段可以组合使用先head -n 200 file | tail -n 50意思是取前200行里的最后50行相当于第151到第200行。这个方法虽然笨但在没有sed习惯的人手里非常直观。3.2 grep的常用组合与正则入门grep是内容检索的一把好手。基本用法grep keyword file会打印包含关键词的所有行。常用参数有-i忽略大小写-n显示行号-r递归搜索目录-v反向匹配输出不包含关键词的行-c只统计匹配行数。实际工作中我最常用的是组合grep -in搜索日志关键词并带上行号方便之后用sed定向查看上下文。比如排查某个订单报错可以先grep -n ERROR /var/log/myapp/app.log | tail -20然后取最后一行的行号配合sed -n 3020,3050p查看那一段完整日志。正则表达式是grep真正的威力所在。默认grep用的是基础正则、?、|这些字符需要转义。不想记转义规则的话直接加-E使用扩展正则。比如查找包含error或warning的行grep -En error|warning app.log还有几个日常高频用法^匹配行首$匹配行尾[0-9]匹配数字.*匹配任意多个任意字符。想提取IP地址可以用grep -Eo [0-9]\.[0-9]\.[0-9]\.[0-9]-o只输出匹配的部分而不是整行。这个技巧在分析访问日志时非常实用。3.3 日志排查从tail到grep的一条龙排查线上问题我通常会按这样的顺序操作先tail -n 100 app.log看看最近的日志长什么样能对整体情况有个感觉。再grep -n ERROR app.log | tail -20定位最近的错误位置。接着用sed打印错误前后约50行把上下文完整还原出来。如果错误出现了很多次还可以统计频率grep TimeoutException app.log | wc -lwc -l统计行数。这只是最简单的计数想按类型分类可以用sort | uniq -c组合grep -Eo TimeoutException|NullPointerException|IOException app.log | sort | uniq -c | sort -nr这条管道的意思是把每种异常分别提出来排序后统计每种异常出现次数再按次数倒序排列。整个排查过程不用打开编辑器终端里就能完成效率高得多。需要注意日志量特别大时grep一个几百MB的文件可能会等好几秒。如果文件是压缩归档的app.log.1.gz先用zgrep可以直接搜索压缩包内容省去解压步骤速度也还不错。4. 权限、用户和进程理解系统运行的关键权限和进程是Linux日常使用中绕不开的两个模块。不加理解地敲chmod 777虽然能解决问题但它带来的隐患比收益大得多。4.1 chmod数字权限的计算逻辑chmod的数字权限其实就是一个简单的加法映射读是4写是2执行是1三者求和就是一组权限。比如7 421表示可读可写可执行6 42表示可读可写5 41表示可读可执行。常见的chmod 755 file含义是属主拥有全部权限7组拥有读和执行权限5其他用户也拥有读和执行权限5。这个权限组合特别适合一个需要被大家读取和执行的脚本但不希望别人修改它。如果你想在原有权限基础上加一条执行权限可以用符号模式chmod x script.sh。想把属主加写权限、同时去掉其他用户的读权限可以写chmod uw,o-r file。符号模式的好处是只动指定部分不像数字模式必须一次性写出完整的三组权限。很多运维更喜欢符号模式因为改动的意图在命令里一目了然。递归修改权限时用-Rchmod -R 755 /home/project。这里要特别提醒不要随意对整个项目用统一的数字权限。目录一般需要x权限才能进入而普通文件不需要执行权限统一755会导致大量普通文件被加上执行权限既不美观也存在安全隐患。稳妥的做法是用find分别处理find /home/project -type d -exec chmod 755 {} \; find /home/project -type f -exec chmod 644 {} \;这样目录和文件各得其所是我比较推荐的习惯。4.2 进程查看与处理的配合查看进程最常用的是ps。ps -ef显示全部进程输出包含PID、父进程PID、启动时间和命令ps aux也是全部进程但会额外显示CPU和内存占用百分比。两者信息侧略有区别我习惯用ps -ef看进程树用ps aux --sort-%cpu看资源占用。配合grep可以快速找到某个服务ps aux | grep myapp但这样会把自己这条grep命令本身也当成一条结果所以你会看到一行类似grep --colorauto myapp的进程。如果不希望它出现可以写成grep -v grep排除或者用更规范的pgrep -f myapp直接拿到PID。top是动态刷新进程列表的利器类似任务管理器。按P键按CPU占用排序按M键按内存占用排序按q退出。top输出里最值得关注的是load average它表示最近1分钟、5分钟、15分钟的系统负载。不同核心数对应不同的健康标准单核系统负载超过1.0就说明CPU开始排队了8核系统负载到8.0才达到临界。很多人一看到负载高就慌其实要先想清楚机器核心数。要关闭一个进程用kill PID它会发送终止信号。如果进程不响应用kill -9 PID强制结束。-9是最后手段因为进程没有机会清理资源。排查时先看这个进程有没有子进程最好先把子进程处理好否则会留下孤儿进程。我还会养一个习惯kill之前先确认PID的进程确实是我要找的服务不信手拈来曾经因为看错PID误停过同事的开发服务对方一个下午白干。5. 系统资源与网络命令定位问题必备系统资源类命令解决两类问题空间不够了、内存不够了。网络命令解决另一类问题连不上、端口不通。这些都是Linux日常维护绕不开的。5.1 磁盘、目录大小与内存查看df -h查看磁盘分区使用情况。-h以可读格式显示输出里的Use%列直接告诉你用了多少。当某个服务莫名写不了数据时先看一眼df -h很可能就是/分区满了。磁盘满时文件还是能创建吗答案是不一定取决于是否还有inode可用。df -i查看inode使用情况inode耗尽时即使空间还有余也会提示“No space left on device”这个坑比较隐蔽。du -sh查看当前目录总大小du -sh *可以列出当前目录下每一项的大小是找“哪个目录最占空间”的常用招。想深入一层可以用du -h --max-depth1控制输出深度。清理空间时先定位大目录再用前面提到的find按时间删除旧文件这样的流程最稳妥。free -h查看内存使用情况。这里要特别解释buff/cacheLinux会把空闲内存拿来做文件缓存看起来好像用了很多内存其实这部分在需要时可以被回收。所以重点看available列而不是used列后者会包含大量缓存导致误判。曾经帮人排查一台“内存占用95%”的机器最后发现available还有一大半缓存被误当成实占问题其实不存在。5.2 网络连通性与端口排查ping是最基本的连通性测试命令通过ICMP协议发包检测目标是否可达。它能说明网络通不通但说明不了端口是否开放。很多新人以为ping通了服务就肯定能连实际上防火墙可以允许ping但封掉业务端口。排查“连不上某个端口”的问题先查看本机端口监听情况。比较新的系统推荐用ss -tlnp它会列出所有TCP监听端口对应的进程。-t只看TCP-l只看监听状态-n不解析服务名直接显示端口号-p显示进程信息。老系统可能没有ss用netstat -tlnp效果类似。如果服务监听在回环地址127.0.0.1外部机器没可能访问必须把监听地址改为0.0.0.0或具体网卡地址。这个原因在排查“服务明明启动了但外部访问不了”时经常出现值得先记住。curl是测试HTTP服务的利器。最基本的是curl http://127.0.0.1:8080/health查看接口是否返回。加-I只查看响应头加-v显示完整交互过程能直观看到TLS握手、请求头、响应状态等信息。日常调试接口时curl -s -X POST http://127.0.0.1:8080/api/user -H Content-Type: application/json -d {name:test}这种写法能解决不少临时测试需求。6. 打包压缩与软件安装的思路打包和软件安装表面上各是一类命令但思维方式是相通的它们都帮你把“多个东西”规范地归拢或分发好。6.1 tar命令的常用组合tar最初的名字叫“磁带归档”如今更多用于打包和压缩。最常用的组合是tar -czvf archive.tar.gz /path/to/dir拆开看-c创建归档-z用gzip压缩-v显示处理文件列表-f指明明档文件名。解压时把-c换成-xtar -xzvf archive.tar.gz想解压到指定目录加-Ctar -xzvf archive.tar.gz -C /tmp有一个很多人踩过的坑用通配符打包文件时忘记排除日志目录。比如tar -czvf backup.tar.gz /home/project/*.py /home/project/logs会把整个logs目录也打进去备份文件瞬间膨胀。正确的做法是用--exclude排除tar -czvf backup.tar.gz --excludelogs /home/project--exclude要放在源路径之前放在后面有时会被当成需要打包的文件名行为比较反直觉写的时候务必注意。解压前想预览归档内容不实际解压tar -tzvf archive.tar.gz | head -20这条命令只列出归档里的文件清单适合确认归档内容是否正确省去解压后发现多了奇怪文件的麻烦。6.2 包管理器帮你做了什么Linux发行版分成两大流派Debian系的apt和Red Hat系的yum/dnf。它们背后的逻辑是一样的从软件仓库下载预先编译好的二进制包自动解决依赖关系统一安装到系统目录。安装软件前先更新索引Debian系是sudo apt updateRHEL系是sudo yum makecache。更新完再安装sudo apt install nginx包管理器会把nginx需要的所有动态库和子组件一起装上。这个机制大幅降低了手动编译源码时的依赖难题。手动编译安装也不是完全没用比如某些场景需要自定义编译参数或新版本尚未进入仓库。标准的编译三部曲是./configure --prefix/usr/local/myapp make sudo make install但手动编译的软件不会自动注册到包管理器里卸载时只能靠手动删除依赖关系也无人帮忙维护。如果不是有特殊需求我建议优先用包管理器省下的时间足够你多做很多事。有一类情况容易混淆某些软件用包管理器装完执行命令时提示command not found。多数原因是命令不在当前用户的PATH里。比如apt install postgresql后psql可能安装在/usr/lib/postgresql/15/bin/psql而这个路径不在普通用户的PATH里。解决方式是用which psql或find /usr -name psql找到实际位置再考虑加软链接或用绝对路径执行。7. 高频问题与排查实录这个章节我把平时被问得最多的几类问题整理成速查表同时分享几个我本人踩过不止一次的坑给大家提个醒。7.1 常见问题速查表症状可能原因常用排查命令Permission denied文件/目录权限不足ls -l查看权限id查看当前用户command not found命令未安装或不在PATHwhich 命令名、find /usr -name 命令名No space left on device磁盘满了或inode耗尽df -h、df -i端口被占用已有进程监听同一端口ss -tlnp、lsof -i:8080服务启动后外部访问不了监听地址是127.0.0.1ss -lnt查看监听地址检查防火墙kill不掉进程进程处于不可中断状态先查子进程最后用kill -9解压后文件属主不确定压缩包内保留原始属主解压后用chown -R修正属主这里需要强调的是排查看的是“证据链”不是“感觉”。遇到问题时先收集信息当前用户身份、文件权限、端口状态、磁盘余量再逐层缩小范围一上来就猜原因往往会走弯路。7.2 几个我踩过好几次的坑第一个坑是rm的通配符误删。有一次我在/opt/app目录下想删除所有.tmp文件敲的时候多打了一个空格变成了rm *.tmp的两个命令拆分这里其实不能怪通配符而是要多看一眼再回车。我的自我要求是凡是涉及rm的命令先加echo试运行一遍。比如echo rm -rf /opt/app/out/*确认输出里的路径和文件列表符合预期后再把echo去掉执行。别嫌麻烦这一步能救回不少后悔药。第二个坑是cp覆盖文件时不提示。cp默认会直接覆盖同名文件终端没有任何提醒。想获得提示可以加-i参数想强制覆盖可以加-f先想清楚再覆盖才稳妥。有些系统把cp设置了别名默认就带-i但有些系统没有行为不一致依赖默认行为并不可靠。第三个坑是tar解压时覆盖同名文件。tar解压行为同样是直接覆盖如果目标目录里已有重要文件建议先解压到一个临时目录确认后再手动覆盖。比如先解压到/tmp/extract_here看一眼文件列表再决定如何处理。第四个坑和sudo有关sudo echo xxx /etc/foo.conf这种写法在普通用户Shell里会先执行重定向而重定向发生时还没有权限提升所以提示Permission denied。正解是先写入一个临时文件再sudo cp到目标位置或者更推荐用sudo teeecho xxx | sudo tee /etc/foo.conf这个坑很少有人提前讲遇到一次就记住了。最后再分享一个小技巧如果你经常在多个服务器之间操作建议把常用的.bashrc配置统一维护一份里面放几条自己习惯的别名比如alias llls -alhF、alias grepgrep --colorauto。别看只是少敲几个字符日常体验的提升非常明显。Linux命令的掌握本质上是一个“攒肌肉记忆”的过程先把核心命令用顺再按需扩展比我当初拿着命令大全一顿背的效率高得多。