我们经常在各类教程、面试题、项目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总让你加sudo
Linux的权限模型可以用一个简单例子理解:一个文件能被谁读、写、执行,由三组权限决定,分别对应文件所属用户、所属组、其他用户。每组权限用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 *.log,Shell会先把*.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这类文件,可以借助find:
find . -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、tail
cat最适合查看短小而完整的文件内容。它会一次性把所有内容输出到终端,文件一大就刷屏,而且终端缓冲有限,前面的内容根本看不全。要查看完整文件但文件很长时,多用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= 4+2+1,表示可读可写可执行;6= 4+2,表示可读可写;5= 4+1,表示可读可执行。
常见的chmod 755 file含义是:属主拥有全部权限(7),组拥有读和执行权限(5),其他用户也拥有读和执行权限(5)。这个权限组合特别适合一个需要被大家读取和执行的脚本,但不希望别人修改它。
如果你想在原有权限基础上加一条执行权限,可以用符号模式:chmod +x script.sh。想把属主加写权限、同时去掉其他用户的读权限,可以写chmod u+w,o-r file。符号模式的好处是只动指定部分,不像数字模式必须一次性写出完整的三组权限。很多运维更喜欢符号模式,因为改动的意图在命令里一目了然。
递归修改权限时用-R:chmod -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 --color=auto 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-depth=1控制输出深度。清理空间时先定位大目录,再用前面提到的find按时间删除旧文件,这样的流程最稳妥。
free -h查看内存使用情况。这里要特别解释buff/cache:Linux会把空闲内存拿来做文件缓存,看起来好像用了很多内存,其实这部分在需要时可以被回收。所以重点看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换成-x:
tar -xzvf archive.tar.gz想解压到指定目录,加-C:
tar -xzvf archive.tar.gz -C /tmp有一个很多人踩过的坑:用通配符打包文件时忘记排除日志目录。比如tar -czvf backup.tar.gz /home/project/*.py /home/project/logs,会把整个logs目录也打进去,备份文件瞬间膨胀。正确的做法是用--exclude排除:
tar -czvf backup.tar.gz --exclude="logs" /home/project--exclude要放在源路径之前,放在后面有时会被当成需要打包的文件名,行为比较反直觉,写的时候务必注意。
解压前想预览归档内容,不实际解压:
tar -tzvf archive.tar.gz | head -20这条命令只列出归档里的文件清单,适合确认归档内容是否正确,省去解压后发现多了奇怪文件的麻烦。
6.2 包管理器帮你做了什么
Linux发行版分成两大流派:Debian系的apt和Red Hat系的yum/dnf。它们背后的逻辑是一样的:从软件仓库下载预先编译好的二进制包,自动解决依赖关系,统一安装到系统目录。
安装软件前先更新索引:Debian系是sudo apt update,RHEL系是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 | 命令未安装或不在PATH | which 命令名、find /usr -name 命令名 |
No space left on device | 磁盘满了或inode耗尽 | df -h、df -i |
| 端口被占用 | 已有进程监听同一端口 | ss -tlnp、lsof -i:8080 |
| 服务启动后外部访问不了 | 监听地址是127.0.0.1 | ss -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 tee:
echo "xxx" | sudo tee /etc/foo.conf这个坑很少有人提前讲,遇到一次就记住了。
最后再分享一个小技巧:如果你经常在多个服务器之间操作,建议把常用的.bashrc配置统一维护一份,里面放几条自己习惯的别名,比如alias ll='ls -alhF'、alias grep='grep --color=auto'。别看只是少敲几个字符,日常体验的提升非常明显。Linux命令的掌握本质上是一个“攒肌肉记忆”的过程,先把核心命令用顺,再按需扩展,比我当初拿着命令大全一顿背的效率高得多。