刚接触Linux的朋友经常问我同一个问题:命令这么多,是不是要把整本手册背下来才能干活?我在服务器上摸爬滚打这些年,回头想想真正高频使用的命令其实很有限,关键在于你愿不愿意把每条命令背后的逻辑搞清楚。这篇东西不是命令字典,而是我从日常排查、脚本编写、系统维护中提炼出来的实操心得,围绕文件操作、文本处理、权限、进程、磁盘和网络这几大块展开,既有最基础的用法说明,也有我不止一次踩过的坑。无论你是刚入门的学生、准备转运维的职场新人,还是想查漏补缺的开发者,照着操作一遍应该都会有所收获。
1. 先拆骨架:命令的本质、PATH、通配符与重定向
很多人怕Linux终端,是因为觉得每条命令都是一个孤立的"咒语",按下回车之后究竟发生了什么完全是个黑盒。但实际上,你敲下去的每一个命令,本质上都是在执行一个小程序。
1.1 命令就是放在特定目录下的可执行程序
你输入ls -l /etc这串字符时,shell(也就是你登录后看到的那个命令行解释器)会按顺序做三件事:解析命令名ls、读取选项-l、接收参数/etc。真正运行的,是系统在PATH环境变量指定的几个目录里找到的ls可执行文件。
# 查看当前环境的PATH echo $PATH # 查看ls命令到底位于哪个目录 which ls type -a ls输出里常见的/usr/bin、/bin、/usr/local/bin就是命令的"仓库"。理解这一点能解决很多困扰:比如你明明安装了一个软件,敲它的命令却提示command not found,多半是安装目录没有加入PATH。同理,有些系统里自带和第三方安装的同一个命令版本不同,which查看的结果就是你实际敲命令时真正触发的那个程序,这个排查思路在环境异常时非常有用。
1.2 选项和参数为什么会存在
命令、选项、参数三者的关系,可以类比成点菜:命令是"厨房",选项是"口味偏好",参数是"具体菜品"。同一个命令放在不同场景下,靠的就是选项和参数来调整行为。绝大多数命令支持-h或--help打印帮助信息,man手册则是更完整的说明书。
# 快速查看用法 ls --help # 查看完整手册,按q退出 man ls我见过不少人在网上复制命令后运行报错,原因就是没有理解选项中单横线和双横线的差异。单横线之后通常跟短选项,双横线后面跟长选项,比如ls -l和ls --format=long是一条命令的两种写法。新手不用追求一次记住全部参数,先把三个最常用的记牢:看懂输出、打印帮助、进入手册,剩下的遇到问题再查,效率反而高很多。
1.3 通配符、重定向和管道:把零散命令串起来的胶水
单条命令能做的事情有限,Linux真正强大之处在于把几条命令组合起来形成"流水线"。
通配符是shell在命令执行前先做的一次文件匹配。*匹配任意多个字符,?匹配单个字符,[...]可以匹配字符集合。
# 删除目录下所有.txt文件,但保留README.txt rm *.txt # 匹配file1.txt、file2.txt这样的文件 ls file?.txt重定向则是把命令的输出不再打到屏幕上,而是写入文件或者追加到文件末尾。其中2>专门重定向错误输出,这个细节很容易被忽略。
# 正确输出写入log.txt,错误输出写入error.txt ./run.sh > log.txt 2> error.txt # 把标准输出和标准错误都写入同一个文件 ./run.sh > all.log 2>&1管道符|则把前一条命令的输出作为后一条命令的输入,这是Linux命令行最迷人的地方。一个经典例子是"查看当前目录下占用空间最大的5个子目录":
du -sh */ | sort -rh | head -5在这里,du负责统计目录大小,sort负责按数值倒序排序,head负责截取前5行。它们各自只做一件事,组合起来就完成了一个相对复杂的查询任务。理解命令的"骨架逻辑"(命令加选项加参数,配合重定向和管道),比死记几十条命令的语法更划算,因为你能通过这个框架自己推导出陌生命令的用法。
2. 文件与目录操作:高频命令背后的细节
文件操作是每天接触最多的部分,但恰恰因为太常用,很多人的使用方式还停留在"能出结果就行"的阶段。
2.1 ls的每一项输出都值得看懂
ls -l是查看文件详情的标配,但这一长串输出里每个字段都有含义,我挑重点拆开讲。
-rw-r--r-- 1 zhangsan devs 2048 Mar 12 10:30 config.ini从左往右依次是:文件类型与权限位、硬链接数、属主、属组、文件大小、最后修改时间、文件名。第一列开头的-表示普通文件,d表示目录,l表示符号链接。接下来9个字符是权限位,分三组:属主、属组、其他人,每组三个字符对应读、写、执行权限。这一列是后面权限章节的核心,现在先混个脸熟。
日常使用中,我建议把ls的个人习惯固定下来:
# 人类可读的大小 + 显示隐藏文件 + 按时间倒序 ls -lh ls -la ls -lt # 目录内容太多,只列目录本身 ls -ld /etc有个小细节容易踩坑:ls -l显示的目录大小并不是目录里所有文件的总和,而是目录条目本身占用的空间。想知道某个目录下所有文件总大小,用du -sh 目录名,别用ls -l。
2.2 cp、mv、rm:哪些操作不可逆
复制命令cp最容易被忽略的选项是-a和-r。很多人知道复制目录要加-r,但-r在权限和时间戳保留上并不彻底。想要完整保留软链接、权限、时间信息,更稳妥的是:
# 完整保留属性的目录复制 cp -a /data/project /backup/projectmv在同文件系统内只是修改名字和目录项,速度极快;但跨越不同文件系统(比如把/home下数据移动到挂载在/data的独立磁盘分区)时,它实际上是"复制数据到新位置再删除旧数据"。所以移动几十GB的大目录时出现卡顿,不一定是机器问题,而是它真的在拷贝。
rm是所有人听过最多警告的命令。我的习惯是:在重要的生产服务器上,不给普通用户(包括自己)的shell配置里放危险的rm -rf别名,而是用一套"软删除"的思维。最简单的办法是把要删的东西先移动到/tmp或者~/trash目录下,观察两天确认无误后再真正清理。
# 软删除:先移动到临时目录 mkdir -p ~/trash mv dangerous_dir ~/trash/ # 确定不需要后 rm -rf ~/trash/dangerous_dir这里还有一个几乎每个老手都踩过的坑:rm -rf /var/log/applogs/*这类写法,如果通配符没有匹配到任何文件,某些shell的历史展开机制可能会把命令变成删除目录本身。严格起见,我是先cd到目标目录,再用相对路径执行清理命令,尽量避免"绝对路径加通配符"的写法。
2.3 找文件的三件套:find、locate、which
find功能最全,但语法最绕。日常我用最多的组合是:
# 按名称找,忽略大小写 find /opt -name "*.conf" -o -name "*.ini" # 找最近一天内被修改过的文件 find /var/log -mtime -1 # 找大于500MB的文件 find /data -size +500M # 找到后直接删除(注意加上完整路径保护) find /tmp -name "*.bak" -mtime +7 -exec rm {} \;初次接触find的人容易混淆-name和-path:-name只匹配文件名,-path会匹配完整路径。比如找/opt/app下所有log相关的文件,find /opt/app -name "*log*"和find /opt/app -path "*log*"的结果可能不一样,后者还会把名为logging的目录带出来。
locate走的是数据库索引,秒级返回结果,但新创建的文件可能不在索引里,需要先执行updatedb刷新。which前面已经介绍过,它只用来查可执行命令的位置,和find定位数据文件的用途不一样。我不会只依赖某一个命令,通常先用locate碰碰运气,没结果再上find。
3. 文本处理三兄弟:grep、sed、awk的实战组合
服务日志、配置文件、接口返回,Linux上大量信息都以文本形式存在。能不能高效提取出自己关心的内容,直接决定排障速度。这里面的主力工具就是grep、sed、awk。
3.1 grep:过滤行是最常用的阅读方式
grep的作用是"按行匹配":从输入中找出包含指定模式的每一行。实战里我几乎只用这些参数:
# 从错误日志里找java异常关键字 grep -i "exception" app.log # 带上下文:显示匹配行的前后5行 grep -C 5 "OutOfMemory" app.log # 只显示文件名和匹配次数 grep -c "ERROR" app.log grep -r -l "timeout" /opt/app/config/-i忽略大小写,-C 5是排障刚需(光看报错那一行往往不知道上下文),-r递归搜索目录,-l只列出文件名。另外,grep默认是基础正则,如果想要更灵活的匹配(比如需要匹配a或b、精确匹配单词边界),要加-E或者-P。
### 3.2 sed:不打开编辑器也能改文件 sed的本质是流编辑器,它逐行读取、按规则处理、再输出。最常见的需求是替换和删除。 ```bash # 把每个月的配置里的IP替换掉 sed 's/192.168.1.10/192.168.1.20/' nginx.conf # 删除配置文件里的注释行和空行 sed -i '/^#/d;/^$/d' nginx.conf # 只打印第10行到第20行 sed -n '10,20p' app.log-i参数表示"原地修改",也就是直接写回文件。这里我必须提醒:线上改配置之前,先把文件备份一份,或先不加-i跑一遍看输出是否符合预期。我在一次批量替换数据库连接串时,因为正则在sed里没有加转义,差点把包含特殊字符的配置改坏,从那以后凡是关键配置文件,我都先复制成.bak再操作。
sed的原理解释一下:它默认把输入流按行切分,s/旧/新/的格式是对每一行做替换,行首的^和行尾的$是正则锚点。多学一个-E扩展正则会轻松很多,比如提取两个标记之间文本这类复杂操作会简单不少。
3.3 awk:列处理的最强武器
awk最直观的价值是按列拆分。日志里常见格式是"IP地址 时间 请求路径 状态码",要统计某个IP的访问量,awk是做这种事最顺手的工具。
# 打印每行第一列(通常是IP) awk '{print $1}' access.log # 打印最后一列 awk '{print $NF}' access.log # 按逗号分隔列 awk -F',' '{print $2}' data.csvawk内置变量NF表示当前行字段数,$NF就是最后一个字段,NR是当前行号。它还能做简单运算和统计:
# 统计所有请求返回的总大小,假设第10列是字节数 awk '{sum += $10} END {print sum}' access.logawk的写法像是微型的编程语言,有变量、条件判断、循环,但新手可以先掌握print、$列号、END这三个概念,绝大多数日志统计需求已经能覆盖。ps:如果你只是想把日志行的部分字符截取出来,先用awk打印列,再叠加sort、uniq做聚合,比写Python脚本快得多。
3.4 经典管道链:一条命令完成访问量TOP10
把grep、awk、sort、uniq串起来,能解决很多看起来"要写脚本"的问题。比如统计访问日志中请求数最多的10个IP:
cat access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -10拆开看每个环节的作用:cat读取日志,awk '{print $1}'抽出IP列,sort把相同IP排到一起,uniq -c统计每个IP出现次数并输出"次数 IP"格式,sort -nr按次数从大到小排序,head -10取前10条。整个链条没有生成任何中间文件,排障时需要在分钟级内出结果,这种管道组合往往比打开大数据分析工具更快。
需要注意的是,如果文件特别大,比如几个GB的日志,别用cat把全文推给管道,直接用grep吞文件能省不少内存和时间:
grep "ERROR" huge.log | awk '{print $2}' | sort | uniq -c | sort -nr | head -204. 权限体系与用户管理:从看懂rwx到sudo的边界
权限问题几乎是Linux新人翻车最多的领域。要么操作时Permission denied,要么图省事全部用root跑,埋下更大的隐患。
4.1 权限位拆解:drwxr-xr-x到底在说什么
前面ls章节提到的权限串,在目录和文件上含义有差异。对于文件,r是读取内容,w是修改内容,x是当作程序执行。对于目录,r是能列出目录内容,w是能在目录里创建或删除文件,x是能否进入该目录(配合cd)。
一个常见的坑:你被赋予了某个目录的r权限,但没有x权限,那ls仍然进不去,因为列出目录内容时需要同时具备"进入"能力。对应的处理办法是检查目录属主和权限位,不要只盯着一项看。
# 查看当前用户 whoami id # 查看文件属主属组 ls -l config.ini # 查看目录权限 ls -ld /etc/nginx4.2 chmod改变权限:符号模式与数字模式
chmod有两种模式。符号模式直观好记:
# 给属主增加执行权限 chmod u+x script.sh # 给属组和其他人去掉写权限 chmod go-w config.ini # 所有人加读权限 chmod a+r readme.txt数字模式则是把权限换算成数值:r=4,w=2,x=1。比如rwxr-xr--可以逐组相加得到754,这在脚本部署时非常常见。
| 权限组合 | 数值 | 典型场景 |
|---|---|---|
| rw------- | 600 | 私密配置文件 |
| rw-r--r-- | 644 | 普通文件默认 |
| rwxr-xr-x | 755 | 可执行程序/脚本 |
| rwx------ | 700 | 私有目录 |
| rwxrwxrwx | 777 | 不推荐,任何人可改 |
我通常给脚本755、给私钥600、给配置目录按需750。777虽然省事,但意味着任何用户都能修改文件,在共享服务器上是明显的安全风险,不建议出现在生产环境。
系统新建文件时的默认权限由umask控制,它决定"要减掉的权限"。多数发行版默认的umask 022表示新建文件会去掉属组和其他人的写权限,所以新文件通常是644,新目录是755。如果团队需要更严格的环境,可以改成umask 027,默认不让其他用户可读。
4.3 用户与组的管理
多人共用一台服务器的情况很常见,给每个人单独建账号比大家都用root更安全,也方便追溯操作记录。
# 添加用户 useradd zhangsan # 设置或修改密码 passwd zhangsan # 把用户加入某个附加组 usermod -aG devs zhangsan # 查看用户所属组 groups zhangsanLinux用户可以有多个组,其中"主组"是用户创建文件时的默认属组,附加组用于赋予额外权限。处理团队协作目录时,我一般会建一个公共组,比如projectx,然后让所有项目成员加入这个组,目录权限设置为2770,这样同组成员都能读写,又不放权给无关用户。
groupadd projectx usermod -aG projectx zhangsan chown -R root:projectx /data/projectx chmod 2770 /data/projectx这里的2是SETGID位,作用是在该目录下新建的文件会自动继承目录的属组projectx,避免出现"A用户创建的文件B用户改不了"的典型问题。
4.4 sudo:授予有限的管理权限
日常操作尽量用普通用户,偶尔需要管理员权限时用sudo,而不是直接切到root。sudo的配置在/etc/sudoers,必须用visudo命令编辑,它会做语法检查,避免配错导致整个sudo无法使用。
# 给用户无限sudo权限(仅限可信环境) zhangsan ALL=(ALL) ALL # 只允许执行几条特定命令 zhangsan ALL=(ALL) /usr/bin/systemctl, /usr/bin/tail注意,允许vim或sed以root身份运行,其实等效于给了用户任意命令执行能力,因为编辑器里可以执行shell命令。所以授权时要按最小权限原则来,别图方便放开整个编辑器。我自己给开发同学开权限时,通常只给日志查看和服务状态查看权限,涉及变更操作的命令都收敛到专门的发布流程里执行。
5. 系统体检:从进程、服务到磁盘的排查顺序
服务器出问题时,我养成的第一习惯不是拍脑袋猜,而是按"进程 - 服务 - 磁盘 - 内存"的顺序逐层看。
5.1 进程管理:ps、top、kill的组合拳
ps是最常用的进程查看命令,组合参数比较多,我固定用几套:
# 查看所有进程的完整信息 ps aux # 查看某个特定进程 ps -ef | grep javaps aux输出的CPU%和MEM%是瞬时值,要看动态变化得用top。top进入交互界面后,按P按CPU排序,按M按内存排序,按q退出。这个动作在排查"哪个进程把CPU吃满"时几乎是肌肉记忆。
top -p 1234如果确认一个进程需要终止,kill默认发送的是TERM信号(编号15),让进程有优雅收尾的机会;实在没反应再使用-9强制结束。
kill 1234 kill -9 1234这里有个新手容易踩的坑:kill -9虽然能把进程干掉,但进程来不及做清理操作,可能留下临时文件、锁文件或者损坏的数据。所以我一般先给默认信号,等几秒没退出再用强杀,日志类程序尤其如此。另外,进程变成僵尸状态(ps输出Z)时,它本身已经结束,只是父进程没有收尸,强杀它没用,得处理父进程,否则系统PID占着会慢慢变少。
服务型进程如果希望它在后台持续跑,最稳妥的是交给systemd托管,nohup只能算应急方案。我见过有人用nohup java -jar app.jar &启动服务,结果终端退出后进程也跟着丢掉的案例,就是没有理解nohup只忽略挂断信号、并不保证守护性。真正常用的是写一个unit文件,让systemd管理自动拉起。
5.2 systemd:服务查看与管理的最小操作集
现代Linux发行版普遍使用systemd,服务管理命令是这套逻辑:
# 查看服务状态,包含最近的错误信息 systemctl status nginx.service # 启动/停止/重启服务 sudo systemctl start nginx sudo systemctl stop nginx sudo systemctl restart nginx # 设置开机自启 sudo systemctl enable nginx排查服务失败时,systemctl status只是入口,真正的日志要交给journalctl:
# 查看某服务最近的日志 sudo journalctl -u nginx.service -n 100 # 跟踪某个服务日志,实时刷新 sudo journalctl -u app.service -f我排障的顺序很简单:先看服务当前状态是active还是failed,再去journalctl里找最后100行。如果日志显示端口被占用或配置文件错误,问题往往就浮出水面了。这个路径比直接翻/var/log下的零散文件要快很多。
5.3 磁盘空间与内存的体检指标
磁盘排查有两个参数最容易混淆:df查看的是文件系统整体使用量,du查看的是某个目录实际占用。比如要找出/var下哪个目录把磁盘塞满了:
df -h sudo du -sh /var/* | sort -hr | head -10如果df -h显示/已经100%,但是du -sh /统计出来的大小却对不上,常见原因是存在被删除但仍被进程打开的大文件。这种情况需要用lsof找出占着空间的文件句柄:
lsof +L1 | awk '$7 > 1000000 {print $1, $2, $4, $7, $10}' | head -20同样值得注意的是inode耗尽导致的假性磁盘满:df -h看着还有空间,但新建文件报错No space left on device。此时用df -i查看inode使用率,多半是某个目录下塞了海量小文件(比如邮件队列、临时缓存)。这类问题的根治办法是清理过期小文件,或让应用改用大目录分区存储。
内存方面,free -h是最直观的命令。留意观察的重点不光是已用内存,还有available字段,它才是估算还能跑多少应用的可靠指标,因为Linux会把空闲内存拿去做页面缓存,真正需要时会释放,所以不要看到used高就恐慌。
free -h实践中的经验是:内存不足导致的性能问题,往往伴随swap的大量使用。当free -h看到swap占用了好几个G,而应用明明有内存可用时,就需要去查是否有进程发生了内存泄漏,这时候可以结合top按内存排序,再观察几次采样值的变化趋势。
6. 网络排查:从连通性到端口的定位思路
网络类问题排查起来最怕没有头绪。我的固定流程是"先连通性,再端口,再接口",每一步都有对应命令。
6.1 连通性与延时:ping的边界
ping用来判断本机能否到达目标主机,基于ICMP协议,它回答的是"网络层面通不通"的问题。
ping -c 5 10.20.30.40但ping不通不代表服务一定不可用,因为很多云环境和安全组会屏蔽ICMP。同理,ping通也不代表目标端口的服务正常,它是一个很粗的探针。所以它只是排查链路的第一板斧,不能因为ping通了就下一个"网络没问题"的结论。
6.2 端口监听与连接状态:ss与netstat
想知道本机某端口是否被服务监听,或者某端口被哪个进程占用,核心命令是ss。
# 查看所有正在监听的TCP端口 ss -tlnp # 过滤出8080端口 ss -tlnp | grep 8080-t表示TCP,-l表示只显示监听状态,-n不解析域名,-p显示进程信息(需要root权限看进程名)。老系统上要用netstat -tlnp,两者思路相同,ss是新工具,信息更全。
如果要测试到远端某个端口通不通,可以用:
# 查看端口是否开放 timeout 3 bash -c 'echo > /dev/tcp/192.168.1.10/3306' && echo "port open" || echo "port closed"这种方式不依赖额外工具,但更通用的做法是nc或telnet。很多生产环境为安全考虑没有安装nc,用上面这个方式也可以临时应急。
6.3 HTTP接口排查:curl是调试利器
排查Web应用时,curl是我最常用的工具。它几乎能模拟所有HTTP请求场景。
# 查看响应头,判断服务和重定向情况 curl -I http://127.0.0.1:8080/health # 查看完整请求与响应,别错过TLS握手细节 curl -v http://127.0.0.1:8080/api/test # 发送JSON格式的POST请求 curl -X POST http://127.0.0.1:8080/api/users \ -H "Content-Type: application/json" \ -d '{"name":"test","age":18}'-v输出的内容里藏着大量信息:域名解析耗时、TCP连接是否建立、TLS版本、HTTP状态码、响应头字段等。接口状态码异常时,我第一步就是用curl -v确认是不是本地网络或者代理在捣乱。如果是内网接口返回超时,可以尝试给curl设置超时时间,避免等太久:
curl --connect-timeout 3 --max-time 10 http://example.com/如果遇到"页面能打开但接口超时"的问题,我会把排查顺序定为:先ss -tlnp确认服务在监听,再curl本机地址确认服务本身是否正常,再测外部访问地址,最后检查防火墙规则和服务配置里的监听地址。很多时候问题并不在应用代码,而是服务只监听了127.0.0.1,外部请求自然到达不了。
这块还容易忽略的是防火墙:云环境里的安全组和本机iptables/firewalld是两层防线。客户反馈某个端口不通时,别只看本机防火墙,还要看安全组是否放行。曾经某个服务排查了半天,最后发现是本机firewalld默认屏蔽了非默认端口,一条firewall-cmd --add-port=8080/tcp --permanent就解决了。
7. 给刚起步的朋友几条实用建议
最后分享几个我长期坚持的小习惯。第一个是给高频命令设置别名,我自己在.bashrc里固定了这几条:
alias ll='ls -l --color=auto' alias la='ls -la' alias grep='grep --color=auto' alias df='df -h' alias du='du -sh'这些别名不改变命令本质,只是让我在结果输出时更快定位信息。第二个习惯是遇到危险命令先echo一遍,把要执行的命令打印出来确认无误再真正执行,尤其是涉及rm和批量替换的场合。第三个习惯是学会看帮助信息,碰到不熟悉的命令我先man一下,比直接去搜复制粘贴要可靠,至少能避免版本差异带来的坑。
命令这东西,不是背得越多越厉害,而是遇到问题时能准确找到合适的工具并正确使用。我在服务器上最熟练的其实始终是那几十条命令,但它们之间的组合方式千变万化。希望这篇文章能帮你把最核心的几条主线吃透,剩下的,都是在实际场景中遇到一次、解决一次,自然就长在肌肉记忆里了。