1. 为什么Python程序员绕不开Linux:从一次线上事故说起
先讲一件真实经历。之前负责维护一个爬虫服务,本地Windows上跑得好好的,每十分钟抓一次数据,稳定运行了快一周。结果一部署到云服务器上,不到半天就挂了。远程连上去一看,进程还在,但日志文件已经膨胀到4个G,磁盘直接写满,MySQL连不上,整个服务链全崩。那次排查花了我将近三个小时,最后发现罪魁祸首是一行print——没错,就是Python里最常见的调试输出,在本地跑的时候终端能看到,但到了Linux后台用nohup启动之后,标准输出被重定向到了日志文件,每抓一次数据就写几百行日志,几分钟就能写满磁盘。
这个事故让我彻底明白了一件事:写Python代码只是工作的一半,另一半是让代码在Linux环境下稳定运行。Python是跨平台的语言,但Python程序员的工作环境几乎必然包含Linux——开发机可能是Windows或macOS,但代码最终要跑在Linux服务器上、跑在Docker容器里、跑在云函数中。如果只会写代码,不会用Linux命令去观察、定位、处理问题,出了问题就只能干瞪眼,连排查的入口都找不到。
这篇文章不是让你把Linux命令大全背下来,而是从Python程序员真实的工作流出发,挑出日常开发、调试、部署、排障中最常用、最能救命的那些命令,配合实际场景讲解。我尽量把每个命令的适用场景、常见坑、组合用法都讲透,让你看完能直接用到工作中。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 文件与目录操作:先看清楚“战场”再动手
Python程序员在Linux上做文件操作,通常不是为了打命令而打命令,而是带着明确目的:项目部署、日志清理、数据文件处理、配置文件修改。这几个场景对应的命令并不复杂,但组合起来能解决大部分问题。
2.1 ls、du、df:磁盘和文件状态一眼看穿
先说最基础的ls。很多教程只教你ls -l看权限,但实际工作中我最常用的是ls -lh,加一个h参数,文件大小会以人类可读的格式显示,ls -l显示的是字节数,一个日志文件显示成20485760你还得心算这是20M还是200M,ls -lh直接显示20M,一眼就知道该不该清理。
bash复制ls -lh
# -rw-r--r-- 1 root root 20M Sep 12 10:23 app.log
du命令用于统计目录占用空间,排查“服务器磁盘满了但不知道谁占的”这类问题最有用。我常用的组合是:
bash复制# 查看当前目录下每个子目录占用大小,按人类可读格式显示
du -sh *
# 查看当前目录占用总大小
du -sh .
s表示汇总,h表示人类可读。du -sh *会把当前目录下每个文件夹和文件的大小列出来,大到小的排序用管道接一个sort -hr:
bash复制du -sh * | sort -hr
df用来查看磁盘整体使用情况,df -h一眼就能看出哪个分区满了。这里有个Python程序员容易踩的坑:很多云服务器数据盘挂载在/data或/home下,而系统盘在/,代码默认装到/root或/var下,分区满了的表现就是程序突然报No space left on device,但你看代码目录明明还有空间。所以排查这类问题第一步就是df -h,先确认是哪个分区满了。
2.2 find + grep:在文件堆里精准定位
find是Python程序员处理批量文件时的利器,尤其是当你不想写Python脚本去遍历目录的时候——对,很多时候一条find命令比写十几行os.walk更高效。最常用的几个场景:
bash复制# 查找所有Python文件
find . -name "*.py"
# 查找最近7天内修改过的文件
find . -name "*.py" -mtime -7
# 查找并删除所有__pycache__目录
find . -type d -name "__pycache__" -exec rm -rf {} +
第三个命令非常实用。Python项目跑久了,每个包目录下都会生成__pycache__文件夹,里面是一堆.pyc缓存文件。在代码迭代频繁的项目里,这些缓存有时候会导致你明明改了代码却不生效——因为解释器优先加载了缓存文件。我习惯在每次大版本迭代后清理一次:
bash复制find . -type d -name "__pycache__" -exec rm -rf {} +
grep则是搜索文件内容的利器,通常和find配合形成完整方案。比如线上出了bug,你怀疑是某个配置导致的,但不确定配置在哪个文件里,可以这样搜:
bash复制# 在当前目录的所有.py文件中搜索包含"DEBUG"的行
grep -rn "DEBUG" --include="*.py" .
# 忽略node_modules、venv等目录的搜索
grep -rn "DEBUG" --include="*.py" --exclude-dir=venv --exclude-dir=.git .
-r是递归,-n是显示行号。这个组合在排查“配置到底有没有生效”这类问题时非常好用。比如环境变量配了DEBUG=True,但代码里走的分支不符合预期,直接grep一下所有引用点,立刻能定位到是哪个文件的哪个逻辑在作怪。
2.3 一个实例:从“磁盘满了”到“找到元凶”的完整过程
有一次线上告警说磁盘使用率超过90%,我登录服务器后是这么排查的:
bash复制# 第一步:确认哪个分区满了
df -h
# 第二步:进入代码部署目录,看哪个子目录占用最大
cd /opt/myproject
du -sh * | sort -hr
# 第三步:进入占用最大的目录,按文件大小排序找大文件
cd logs
ls -lhS | head -20
ls -lhS的S参数表示按文件大小排序,配合head取前几条,马上就能看到是不是有超大日志。那次找到的是一个debug.log,已经涨到7个G,因为某次上线时有人把日志级别从INFO调成了DEBUG,导致每一条API请求都会记录完整的请求体和响应体。这种问题如果你不会用这几个命令,可能要在服务器上翻半天才能找到原因。
提示:
ls -lhS按文件大小降序排列,head -20只显示前20行。这个组合比du定位单文件更快,因为du主要用于目录,ls -lh加S排序能直接秒杀大文件定位。
3. 进程管理:让Python程序“活着”且“健康”
Python程序员最怕的几件事:服务挂了、服务假死(进程还在但不响应)、CPU被打满、内存泄漏。这些问题的排查和处理,靠的就是进程管理命令。
3.1 ps与top:盯住进程状态和资源占用
ps -ef是最常用的进程查看命令,-e表示显示所有进程,-f表示全格式输出。配合grep可以快速找到目标进程:
bash复制ps -ef | grep python
这会输出所有包含“python”关键字的进程。我的个人习惯是加一个--color=always参数:
bash复制ps -ef --color=always | grep python
这样关键字会以红色高亮显示,在密密麻麻的输出行里一眼就能锁定。
但ps是静态的一次性快照,要看进程的动态资源占用,必须用top。top启动后默认按CPU占用率排序,在界面里按Shift+M可以按内存排序,按c可以显示完整的命令行。
这里有个Python程序员必须知道的细节:在top里看到的Python进程,如果只是一个Python脚本,默认只会显示python3,你不会知道它跑的是哪个脚本。真正专业的做法是在代码里用setproctitle设置进程名,或者在启动时用python3 -m my_script的方式运行。另一个技巧是用top -p指定PID:
bash复制# 先找到进程号
ps -ef | grep my_script.py | grep -v grep
# 假设PID是12345,只监控这个进程
top -p 12345
3.2 kill与kill -9:停止Python进程的正确姿势
这个话题看着简单,但实际操作中很多人会卡在“进程停止不了”的问题上。最常规的停止方式是:
bash复制# 先找到PID
ps -ef | grep my_script.py | grep -v grep
# 温和地请求进程退出
kill 12345
# 等几秒后如果还在,强制终止
kill -9 12345
kill默认发送SIGTERM信号,相当于礼貌地请求进程退出,Python进程会触发atexit清理逻辑。kill -9发送SIGKILL,直接由内核终止进程,Python的清理逻辑不会执行。
有一个真实场景:写了一个定时任务脚本,每次跑完都会正常退出,但某次数据量暴增,脚本跑了一下午还没结束。我想让它停下来,一个kill下去,等了10秒进程还在,因为那个脚本正在执行一条巨长的数据库查询,SIGTERM被Python解释器接收后要等当前指令执行完才会响应。这时候只能kill -9强杀。但这也是有代价的——如果是写入一半的数据库操作,可能留下脏数据。
所以我总结的经验是:先kill,给它一段合理的时间(比如30秒),确实退不出去再kill -9。
3.3 nohup、setsid、systemd:让Python程序在后台稳定运行
开发阶段直接在终端跑python app.py没问题,但生产环境不行——终端一关,进程就跟着没了,因为SIGHUP信号会发送给所有挂在终端上的进程。解决办法有几种:
bash复制# 方式一:nohup + 后台运行
nohup python app.py > app.log 2>&1 &
# 方式二:用setsid
setsid python app.py > app.log 2>&1 &
# 方式三:nohup不指定输出文件,日志输出到nohup.out
nohup python app.py &
这里面最容易踩的坑是重定向顺序。nohup python app.py > app.log 2>&1 &的意思是:标准输出重定向到app.log,然后标准错误也重定向到标准输出当前指向的地方,也就是app.log。如果你写成nohup python app.py 2>&1 > app.log &,标准错误会被重定向到终端而不是日志文件,等你关了终端,错误信息就全部丢失了。
另外,2>&1必须放在> app.log后面,前面的>会把标准输出指向app.log,接着2>&1才会把标准错误也指向同一个文件。
对于更正式的服务,用systemd写一个service文件是更好的选择。现在主流Linux发行版都使用systemd作为init系统,很多教程里还在用service命令,但实际上service只是个兼容层。一个最简单的service文件长这样:
ini复制[Unit]
Description=My Python API Service
After=network.target
[Service]
ExecStart=/usr/bin/python3 /opt/myproject/app.py
WorkingDirectory=/opt/myproject
Restart=always
RestartSec=5
Environment="PYTHONUNBUFFERED=1"
[Install]
WantedBy=multi-user.target
配置好之后:
bash复制# 重新加载配置
systemctl daemon-reload
# 启动服务
systemctl start my-api
# 设置开机自启
systemctl enable my-api
# 查看服务状态
systemctl status my-api
# 查看服务日志
journalctl -u my-api -f
这里有个细节我特别强调:Environment="PYTHONUNBUFFERED=1"这行。Python的默认行为是标准输出在非交互环境下是块缓冲的,也就是说日志不会立即写入文件,而是攒够一定量才写。这会导致一个问题:程序崩溃时,最后的日志可能还在缓冲区里没来得及写入文件,你看到的最后一条日志停在崩溃之前很久的位置,排查起来特别被动。加上PYTHONUNBUFFERED=1,强制Python实时刷新标准输出,日志才能真实反映程序的实时状态。
4. 日志分析:用“管道组合拳”从海量日志里捞出关键信息
写Python代码的时候,print和logging是日常操作。但日志一旦写到文件里,你再也不能用终端窗口的滚动来看了,必须学会在命令行里处理文件内容。Linux的管道设计(|)就是为了解决这类问题——把前一个命令的输出作为后一个命令的输入,一层层过滤,直到拿到想要的结果。
4.1 tail、grep、awk、sed的协作
tail可能是日志分析中用得最多的命令。tail -f可以实时跟踪文件新增内容,就像在IDE的控制台里看print输出一样,排查线上问题时这个命令几乎必用:
bash复制# 实时查看最新日志
tail -f app.log
# 查看最后100行
tail -100 app.log
但日志一多,光靠tail就不够用了,这时候grep派上用场:
bash复制# 查找最新的报错信息
tail -1000 app.log | grep -i "error"
# 查找某个用户ID相关的所有日志
tail -5000 app.log | grep "user_12345"
这个组合很好理解。tail -1000先取出最近1000行日志,grep再在这1000行里过滤出包含“error”的行。为什么不是直接grep -i "error" app.log?因为日志文件可能好几个G,直接全文件grep既慢又容易被无关的历史噪声干扰,先取最近一段再过滤,效率高而且更贴近“排查当前问题”的目标。
awk的定位更精准一些——处理列格式的文本。日志格式通常是:
code复制2024-12-15 10:23:45,678 ERROR - Failed to connect to database
如果我只想提取“时间+错误信息”这一列,可以用awk做列切割:
bash复制# 按空格分割,$1是日期,$2是时间,$5及之后是错误信息
tail -1000 app.log | awk '$3 == "ERROR" {print $1, $2, $4, $5, $6, $7, $8, $9}'
sed则用于简单的文本替换,最常见的场景是脱敏——日志里有邮箱、手机号等敏感信息,不方便直接发给别人,用sed做批量替换:
bash复制# 把邮箱替换成 *** 之后输出
sed 's/[a-zA-Z0-9._%+-]*@[a-zA-Z0-9.-]*\.com/***@***/g' app.log
4.2 实战案例:从一堆Traceback里捞出真正的原因
有一次同事找我帮忙排查一个Python服务的报错,日志文件里有大量重复的Traceback,刷屏刷得很厉害,肉眼根本看不清第一次报错到底发生在哪里。我的排查思路是:
bash复制# 第一步:统计每种错误出现的次数,从高到低排序
grep -E "^(Traceback| File |.*Error)" app.log | sort | uniq -c | sort -rn | head -30
这条命令的输出会告诉你:哪些错误出现次数最多。但Traceback是多行的,单靠一行匹配会很乱。更实际的做法是:
bash复制# 第一步:找到所有Error关键行的行号
grep -n "Error" app.log | head -20
# 第二步:用sed查看某个行号前后20行的上下文
sed -n '120,180p' app.log
sed -n '120,180p'表示打印第120行到180行的内容。通过行号定位到报错行附近,就能看到完整的Traceback上下文,找到真正的异常原因。
我在实际工作中积累的经验是:Python日志分析,最重要的不是命令本身,而是先把日志格式规范好。用logging模块时配上format参数,把时间、级别、模块名、函数名、行号都打进去,排查问题的效率能提升一倍。日志输出格式可以参考:
python复制import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(levelname)s %(name)s:%(lineno)d - %(message)s'
)
有了带模块名和行号的日志,定位问题时配合grep几乎就是直线命中,根本不需要一行行翻Traceback。
4.3 用wc、uniq、sort做简单的访问统计
有时候不需要写复杂的Python脚本来做数据分析,几条命令组合就能快速出一个统计结果。比如查看一个Nginx访问日志(或你自己程序打印的访问日志),统计每个IP的访问次数:
bash复制# 提取日志中第一列的IP,排序后统计重复次数,再按次数降序排列
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10
这条命令的每一步都值得拆开讲:
awk '{print $1}':取出每行的第一个字段(IP地址)sort:排序,让相同IP相邻排列。注意这里不是可选的,uniq -c只会统计连续重复的行,不排序的话结果就是错的uniq -c:统计每行重复次数sort -rn:-r是降序,-n是按数字排序。没有-n的话,次数会被当成字符串排序,“10”会排在“2”前面head -10:只看前10名
这条组合命令能让我在30秒内回答“今天到底谁在频繁访问”这类问题,应急情况下特别好用。
提示:
sort是这类统计命令链条里最重要的中间环节。写惯了Python的人容易忽略,uniq的“相邻去重”特性决定了必须先sort再uniq,否则统计结果完全错误。
5. 环境与依赖管理:Python环境在Linux上的常见坑
Python环境的痛点,跨平台通用,但Linux上有些坑是Windows/macOS上不太会遇到的。
5.1 which、python3、venv:找到解释器和虚拟环境
很多初学者在Linux上装Python后会遇到“我明明装了Python,为什么python命令找不到”的尴尬。原因很简单:大部分Linux发行版的默认环境里,python指向的是Python 2(有些老系统),或者根本没装Python 2,只有python3。正确做法是创建别名或直接用python3:
bash复制alias python=python3
如果你想让这个别名永久生效,需要写进~/.bashrc:
bash复制echo "alias python=python3" >> ~/.bashrc
source ~/.bashrc
which命令用来查看某个命令的真实路径,排查“命令找不到”时非常有用:
bash复制which python3
# /usr/bin/python3
which pip3
# /usr/local/bin/pip3
如果输出为空,说明命令不在PATH环境变量里。这里可以配合find全局搜索一下:
bash复制find /usr -name "python3*" 2>/dev/null
Linux上的虚拟环境也是Python项目标配。创建和激活的命令:
bash复制# 创建虚拟环境
python3 -m venv venv
# 激活虚拟环境
source venv/bin/activate
# 退出虚拟环境
deactivate
激活后,which python会指向虚拟环境里的Python,而不是系统Python:
bash复制which python
# /opt/myproject/venv/bin/python
这样能确保pip install的包只装在虚拟环境里,不污染系统环境。
5.2 磁盘空间、软链、pip缓存:三个容易忽视的细节
第一个是磁盘空间。Linux服务器往往不只跑一个Python项目,多个项目的虚拟环境加起来,轻松占用十几G。定期用du -sh venv检查一下虚拟环境体积是有必要的。如果发现某个项目的venv占了好几个G,通常是因为里面装了torch、tensorflow这类深度学习库,可以考虑只保留需要的版本。
第二个是软链接。有时候服务器上有多个Python版本,python3指向的可能是/usr/bin/python3.6,而你项目需要Python 3.10。一个常见的做法是用软链接指定默认版本:
bash复制# 给python3.10创建一个软链接,让python3指向它
ln -s /usr/local/bin/python3.10 /usr/local/bin/python3
但这里有个大坑:直接用系统路径下的软链接替换python3,可能导致系统自带的包管理器(比如apt)依赖的Python版本出问题,因为apt本身就是用Python写的。我吃过这个亏,后来学乖了,软链接只改/usr/local/bin或者直接用虚拟环境,不动系统版本。
第三个是pip缓存。pip默认会缓存下载过的包,位置在~/.cache/pip,时间久了也是一个不小的磁盘占用。清理命令:
bash复制pip cache purge
5.3 一个排查案例:“pip install报错但不知道错在哪”
有一次在服务器上执行pip install requests,报了一堆红色错误信息,但没仔细看。我重新跑了一遍,把输出重定向到文件里,然后用grep过滤关键信息:
bash复制pip install requests 2>&1 | tee pip_install.log
# 过滤关键错误信息
grep -iE "error|failed|command not found" pip_install.log | head -20
2>&1 | tee pip_install.log的作用是:把标准错误重定向到标准输出,同时用管道传给tee,tee会同时把内容写到pip_install.log并在终端显示。这样既能看到实时输出,又能保存下来供后续分析。
那次真正的报错是gcc: command not found——安装某些带C扩展的包需要编译源码。解决办法很简单:
bash复制# Debian/Ubuntu系
apt install -y build-essential
# CentOS/RHEL系
yum install -y gcc gcc-c++ make
这个案例说明,排查错误的第一步不是凭记忆猜,而是先把完整报错信息拿到手,再用grep过滤出重点。
6. 文件传输与定时任务:部署阶段的必备技能
写好的Python代码要上传到服务器,日志要定期下载到本地分析,脚本要定时执行——这些场景对应的Linux命令,属于“平时不怎么用,但一旦要用就是刚需”。
6.1 scp和rsync:上传下载文件的两种思路
scp是最直接的文件传输命令,基于SSH协议。用法:
bash复制# 本地文件上传到服务器
scp local_file.py user@server_ip:/opt/myproject/
# 服务器文件下载到本地
scp user@server_ip:/opt/myproject/app.log ./app.log
# 递归上传整个目录
scp -r ./myproject user@server_ip:/opt/
简单够用,但有个痛点:scp每次都会全量传输,即使只有一个字节的改动,也会把整个文件重新传一遍。对于大文件或频繁部署的场景,效率很低。
rsync则是增量传输,只传输有变化的部分,还支持断点续传和压缩:
bash复制# 增量同步本地目录到服务器
rsync -avz --progress ./myproject/ user@server_ip:/opt/myproject/
# 删除服务器上本地已不存在的文件
rsync -avz --delete ./myproject/ user@server_ip:/opt/myproject/
# 只同步.py文件
rsync -avz --include="*.py" --exclude="*" ./myproject/ user@server_ip:/opt/myproject/
参数解释:
-a:归档模式,保留文件权限、时间戳等属性-v:显示详细信息-z:传输时压缩--progress:显示进度--delete:删除目标目录中源目录没有的文件(慎用!)
我的个人经验是:日常小文件用scp快,项目部署用rsync稳。用rsync配合--exclude排除venv、__pycache__、.git这些不需要同步的目录,部署效率能提升好几倍:
bash复制rsync -avz --exclude="venv" --exclude="__pycache__" --exclude=".git" --exclude="*.log" ./myproject/ user@server_ip:/opt/myproject/
6.2 tar、zip:打包与解压的正确姿势
部署代码的时候,经常需要把项目打包上传,或者在服务器上解压一个数据包。tar是Linux上最通用的打包命令:
bash复制# 打包目录(不压缩)
tar cvf myproject.tar ./myproject
# 打包并用gzip压缩
tar czvf myproject.tar.gz ./myproject
# 解压
tar xzvf myproject.tar.gz
# 只查看压缩包内容
tar tzvf myproject.tar.gz
Python项目打包时,我几乎总是需要排除不必要的文件:
bash复制tar czvf myproject.tar.gz --exclude="venv" --exclude="__pycache__" --exclude=".git" --exclude="*.pyc" ./myproject
这个命令结合了前面提到的场景:如果你不小心把虚拟环境一起打包上传,光是tar解压就要多花几分钟,上传时间也翻倍。
6.3 crontab:让Python脚本按计划自动执行
定时任务是服务器上跑Python脚本最常见的方式之一。crontab -e编辑当前用户的定时任务列表,每一行代表一条任务:
bash复制# 每天凌晨2点执行备份脚本
0 2 * * * cd /opt/myproject && python3 backup.py >> backup.log 2>&1
# 每10分钟执行一次数据采集
*/10 * * * * cd /opt/myproject && python3 collect.py >> collect.log 2>&1
# 每天上午9点到下午6点,每30分钟执行一次
*/30 9-18 * * * cd /opt/myproject && python3 check.py >> check.log 2>&1
crontab的五个字段分别是:分钟、小时、日、月、星期。用crontab -l可以查看当前所有任务。
这里有几个Python程序员容易忽略的坑:
第一,cron执行时的环境变量和手动执行时不一样。你的脚本如果在手动执行时正常,但cron里报ModuleNotFoundError,大概率是cron找不到你的虚拟环境路径。解决的办法是在cron任务里显式使用虚拟环境的Python,激活虚拟环境不是必须的:
bash复制0 2 * * * /opt/myproject/venv/bin/python /opt/myproject/backup.py >> /opt/myproject/backup.log 2>&1
第二,cron不会自动进入你的项目目录,所以脚本里不要用相对路径。要么在cron命令里先cd /opt/myproject,要么在Python脚本里用绝对路径。
第三,cron的执行结果会通过邮件发送给当前用户,如果你的服务器没配置邮件服务,这些邮件会在本地堆积,时间久了磁盘又满了。所以每条cron任务最好都加上日志输出重定向,比如上面的>> backup.log 2>&1。
注意:crontab因为不用激活虚拟环境,所以相当于在“裸环境”里执行。凡是用了第三方库的Python脚本,强烈建议在cron里写上虚拟环境python的完整路径,而不是直接用
python3。这个坑我踩过不止一次。
7. 一个完整的排查案例:CPU飙到100%以后我做了什么
把前面讲过的命令串起来,走一遍真实排障流程。有一回线上服务报警:响应时间从300ms涨到10秒,CPU使用率持续100%。我按下面的顺序排查,前后十分钟解决了问题。
7.1 第一步:确认异常进程
bash复制# 看CPU占用排名前5的进程
top -bn1 | head -20
-b是批处理模式(非交互),-n1表示只显示一次就退出。看到排第一的是一个Python进程,PID是28456,CPU占用率300%多(说明多核都在跑)。确认目标:就是它。
7.2 第二步:定位是哪个脚本
单有PID还不够,我得知道这个PID跑的是哪个Python文件:
bash复制# 看看PID对应的完整命令行
ps -ef | grep 28456 | grep -v grep
输出显示:
code复制root 28456 1 0 14:23 ? 00:25:32 python3 /opt/myproject/worker.py
知道了,是worker.py这个后台任务。接下来看它的日志:
bash复制tail -100 /opt/myproject/worker.log
日志显示这个worker应该每30秒处理一批消息,但最近的日志全是同一批消息,处理完一批又一批,像是陷入了死循环。去GitLab上看了一下最近的提交,果然有人改了一处业务逻辑:消费消息后没有更新offset(消息偏移量),导致每轮都重复拉取同一条消息。
7.3 第三步:降级、停止、修复、重启
这个过程算是排障的标准动作。我先停掉这个进程,避免它对线上其他服务造成影响:
bash复制# 先温和停止
kill 28456
# 等5秒,还在
kill -9 28456
然后把代码回滚到上一个稳定版本,重新启动:
bash复制cd /opt/myproject
nohup python3 worker.py >> worker.log 2>&1 &
确认启动正常:
bash复制ps -ef | grep worker.py | grep -v grep
tail -20 worker.log
反应时间立刻恢复了。整个过程核心命令不超过十个,但每一步都建立在“知道用什么命令、为什么用、输出意味着什么”的基础上。
7.4 事后加固:用日志和监控避免同样的事故
这个案例暴露出的一个深层问题是:没有监控报警机制,只能等用户反馈或系统告警才能发现问题。我在事后做了一件很有用的事:把worker脚本的日志从print改成了logging模块,并在每次处理消息后加一行包含消息ID的日志。这样下次再出问题,用grep配合tail就能迅速定位到具体是哪条消息、循环在哪一步。
严格来说,真正生产级的方案是搭建完整的监控告警体系,比如在Python里集成prometheus_client暴露指标,用Grafana看板监控资源占用。但那属于另一篇文章的内容了,如果只是日常应急,学会上面这些命令已经能应付绝大多数突发状况。
8. 几个值得花时间养成的命令使用习惯
文章的最后,我想分享几个在使用Linux命令过程中逐步养成的习惯,这些习惯帮我省了很多时间。
第一个习惯是“先看再动”。在服务器上执行任何可能有副作用的命令(比如rm -rf、rsync --delete)之前,先用ls、find或者rsync --dry-run看一眼效果。像是rsync有一个--dry-run参数,可以只模拟执行不实际同步,我会先用它确认要操作的路径和文件,再真正执行。
第二个习惯是“重要输出重定向存文件”。每次排障时执行的命令,特别是ps -ef、df -h、top -bn1这些,输出都重定向到一个临时文件里,比如ps -ef > /tmp/ps_output.txt。好处是如果后续想回溯当时的系统状态,有据可查。排查完再清掉,不占多少空间。
第三个习惯是“给别名留好位置”。有些命令组合用得太频繁,可以写成别名放进~/.bashrc里。比如我常用的两个:
bash复制alias cls='clear'
alias py='python3'
再进阶一点,还能在~/.bashrc里写简单的函数,比如一个快速查看Python日志的函数:
bash复制function pylog() {
tail -f "$1" | grep -E "ERROR|WARNING|INFO"
}
这样排查日志时直接pylog app.log,比打一长串管道命令省事。
第四个习惯是“用history回顾历史命令”。如果你忘了之前是怎么排查某个问题的,history命令可以看到自己执行过的所有命令。配合grep能快速找到关键命令:
bash复制# 查看历史中所有包含docker的命令
history | grep docker
再配合!直接执行历史命令,比如!123会执行history列表中第123条命令。
最后一个建议:把man当作手册,别怕看英文。遇到不认识的参数,man ls比去搜索引擎查更快,因为man给出的信息是最权威且和你的系统版本完全匹配的。
我在实际操作中最大的体会是:Linux命令不是靠背,而是靠用。今天学一条,明天用一条,两个月下来就能形成肌肉记忆。上面这些命令,我建议你在自己的开发机或虚拟机上先跑一遍,结合自己项目里的场景试着组合使用。等哪天真到了线上出问题、需要快速定位的时候,你会发现这些命令比任何图形化工具都可靠、都飞快。
