多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Python程序员必备Linux命令:从虚拟环境到日志排查的实战指南

Python程序员必备Linux命令:从虚拟环境到日志排查的实战指南 先交代一个背景我在一线写Python的时间不短了从写脚本、做爬虫、跑模型到部署服务、排查线上故障都碰过。今天聊一个很多人问过我的话题——作为Python程序员到底需要掌握哪些Linux命令。先说结论不是要你把Linux系统管理员的命令大全背下来但只要你想把代码放到服务器上跑想自己排查日志和进程问题下面要讲的这套东西是绕不开的。这篇文章会围绕Python开发的真实工作流来拆把高频命令按场景分类讲透告诉你每条命令解决什么问题、为什么这么用、有哪些坑。不管你是刚开始学Python的新手还是已经在写业务代码但一碰服务器就发怵的同学这几页内容都能直接拿来用帮你少走很多弯路。1. 目录导航与查找文件先把工作环境摸清楚1.1 高频目录操作命令很多Python新手最容易忽略的其实是最基础的目录操作。你在自己电脑上双击文件夹很自然但到了服务器上没有图形界面全靠键盘。我见过不少人在服务器上迷路根源就是几个命令没形成肌肉记忆。pwd查看当前所在的路径。每次觉得我在哪的时候就用它别不好意思。ls列出目录内容。加参数更实用ls -lah能看到隐藏文件、权限、大小和修改时间排查问题的时候这信息很关键。cd切换目录。cd ..返回上一级cd -回到之前所在的目录喜欢在几个目录间来回切换时特别方便。tree以树状结构显示目录层级装一下就有tree -L 2只看两层避免输出爆炸。适合快速了解一个项目的目录结构比如拿到一个陌生的Python项目先看它怎么组织的。这里说一个我踩过的坑刚开始用ls看输出以为看到的就是全部文件结果项目跑起来报ModuleNotFoundError排查半天最后才发现有个.env文件被藏起来了。后来我就养成了习惯只要进入一个新目录第一件事先ls -lah把隐藏文件也看一遍。1.2 用find精准定位文件Python项目大了之后文件散落在几十个目录里这个时候靠回忆找文件不靠谱必须用工具。find就是最经典的一个。find . -name *.py当前目录及子目录下找所有Python文件。find . -name *.py -not -path */.venv/*排除虚拟环境目录这个组合我几乎每天都用。虚拟环境里的依赖包太多了不排除的话搜索结果全是噪音。find . -name config*.yaml -mtime -1找最近一天内修改过的配置文件排查问题时往往能快速锁定动过的地方。find . -type d -name __pycache__找出所有缓存目录清理的时候用。我用find解决过一次比较典型的故障测试环境有个服务突然读取不到最新配置大家都很懵。我用find加-mtime找出最近改过的文件顺藤摸瓜发现有人把配置文件改错位置了新文件没被程序读取老文件还在被引用。没有这个命令我可能要把整个项目翻一遍。1.3 grep在代码和日志里做全文搜索grep对Python程序员来说使用频率不比print低多少。你在项目里搜一个函数定义在哪里、查日志里有没有某个报错都离不开它。grep -rn send_email . --include*.py在全部Python文件中递归查找send_email-r是递归-n是显示行号这两个参数我从来都带上。grep -v DEBUG app.log过滤掉包含DEBUG的行日志噪音太大时很有用。grep -E ERROR|WARN app.log | tail -50用正则同时匹配多个关键词再取最后50行查错误基本就是这个套路。个人建议如果你觉得grep写起来还不够快可以试试ripgrep命令是rg搜索速度飞快而且默认就会忽略.gitignore里指定的目录。工具虽小能省下大量等待时间属于谁用谁知道的那种。2. Python运行与依赖管理把环境整明白2.1 虚拟环境的创建、激活与切换Python开发里最容易出问题的不是代码逻辑而是环境。系统Python版本、项目依赖全局安装各种冲突一旦冒出来你会非常头大。虚拟环境就是解决这个问题的标准方案。python3 -m venv .venv在项目目录下创建虚拟环境文件名一般叫.venv。source .venv/bin/activate激活虚拟环境。激活之后命令行提示符前面通常会出现(.venv)标识这时候你执行which python3路径会指向虚拟环境内部。deactivate退出虚拟环境。我见过不少新手踩的坑激活虚拟环境之后发现pip install装的东西好像没生效一查原来是用sudo pip install装的装到系统环境里去了。记住一个原则激活虚拟环境后用which pip或者pip --version检查一下路径确保操作的确实是当前环境的pip再动任何依赖。这个习惯能帮你省下一整天的排错时间。2.2 pip与依赖管理依赖管理是Python开发的日常。不是等报错再处理而是从一开始就养成清晰的习惯。pip list查看当前环境已安装的包。pip freeze requirements.txt把当前环境所有包导出到文件版本号也会带上。你在本地装好依赖后导出这个文件别人在服务器上用pip install -r requirements.txt就能一键复现同样的环境。pip install -r requirements.txt按文件安装依赖部署时最常用的命令。python3 -m pip install requests显式用python3 -m pip而不是直接pip能尽量避免用的pip和当前Python不匹配的问题。这一点在服务器上尤其重要我以前就这么被坑过——系统的pip指向旧版本Python装了个包代码里怎么都导入不了。如果你想让依赖管理再规范一层可以用pip-tools或者uv这类工具通过一个顶层依赖文件生成锁文件确保不同环境安装的版本完全一致。不过这是进阶话题刚开始用好requirements.txt就够了。2.3 运行Python脚本的常用姿势写好的代码最终要靠命令跑起来这里有几个我每天都在用的运行配方。python3 app.py前台运行脚本。但这样终端会被占住也容易因为意外断开SSH而中断进程。python3 app.py app.log 21把标准输出和错误输出都重定向到日志文件再配合下一章的tail -f实时查看进度。21的意思是标准错误也一起写入同一个文件别让报错信息飘在终端里找不着。python3 -u app.py关闭输出缓冲。写日志脚本、实时处理流的场景下不加-u你会发现日志输出有延迟还以为程序卡住了。nohup python3 app.py app.log 21 nohup让进程在终端关闭后继续运行放到后台。这是服务器上跑长任务最典型的命令后面讲进程管理时会再展开。关于修改进程名称其实不算高频需求但如果你确实想把一个Python进程改成容易识别的名字可以在代码里用setproctitle这个库或者启动时用exec -a newname python3 app.py来指定。不过日常维护中更推荐用systemd来管理服务名字和服务本身绑定好认也好管放在第五部分细说。3. 文本处理与日志排查在线排障的核心技能3.1 查看日志的经典组合tail、head、less日志是排查一切线上问题的起点。Python服务的日志可能每小时就写几十MB打开整个文件是不现实的所以你要学会有选择地看。tail -n 100 app.log看最后100行日志相当于看程序最近的运行状态。tail -f app.log持续跟随文件的输出新日志实时滚动显示。部署服务、测试接口时开一个窗口挂着tail -f看到新日志心里就有底。想退出就按Ctrl C它只是停掉跟随不会影响服务本身。head -n 50 app.log看文件开头50行日志轮转后排查最初的报错时有用。less -N app.log分页查看大文件-N显示行号。在less里按/直接搜关键词按n跳到下一个匹配。相比vim直接打开几百MB的日志less打开大文件的效率高得多也不会因为文件太大把内存吃满。我个人感受排查问题的时候顺序通常是tail -f观察现象-grep定位关键字-less看上下文。能同时掌握这三个工具的组合用法就已经超过不少人了。3.2 文本处理管道sed、awk、sort、uniqPython本身处理文本很强但在服务器上用sed、awk做快速统计和清洗效率往往比写个Python脚本高得多因为不用启动解释器、不用写文件、不用等执行。处理的都是一次性任务管道组合下来一行命令就搞定了。sed -n 100,120p app.log只查看第100到120行定位问题上下文的利器。sed s/ERROR/WARNING/g app.log把日志里的ERROR替换成WARNING输出。虽然这个例子在真实场景里用得不多但你理解语法后就能迁移到各种替换场景比如批量修改配置文件里的路径。awk {print $1} access.log按空格分隔取第一列。Apache/Nginx访问日志取IP就靠这条。awk -F, {sum $3} END {print sum} data.csv把CSV文件按逗号分隔累加第三列并输出总和。处理几百万行的统计任务这个写法比Python脚本简洁不少。sort | uniq -c | sort -rn | head -20统计出现次数最多的前20个值。查日志中出现最频繁的报错、统计访问量最高的IP都是这套组合拳。我记得有一次查一个线上接口为什么变慢就是靠awk从访问日志里按状态码分组统计然后sort -rn看哪个状态码异常多很快锁定了一批5xx请求来自同一个来源IP。整个过程没写一行Python代码但效率比写脚本高了好几个量级。3.3 JSON日志与jqPython后端服务现在很多都用JSON格式输出日志。JSON结构化了但人眼直接看很累这时候需要jq它就像命令行版的json.loads。cat app.json | jq .格式化JSON输出层级清楚一眼看清结构。jq .level, .message app.json只取日志级别和消息字段。jq select(.level ERROR) app.json筛选出级别为ERROR的日志。jq .items[] | {id, name}遍历数组并提取字段接口返回数据调试时非常顺手。可能有读者会问我用Python的json.loads一样能解析为什么要学jq我的答案是工具链的效率差别。你开着日志文件想快速筛一个字段一条命令几毫秒就出结果不必打开REPL一行一行写处理逻辑。尤其服务器上不一定有你的Python虚拟环境而jq几乎是标配。4. 进程管理与后台任务让服务稳定地跑起来4.1 查看进程与资源占用把Python服务部署到服务器后第一步永远是确认进程状态还在吗活着吗吃了多少内存这些问题靠下面的命令回答。ps aux | grep python3列出所有含python3关键词的进程。这是最快确认我的服务有没有在跑的方法。ps aux --sort-%mem按内存占用从大到小排列。排查服务器内存怎么又满了的时候一眼就能看到谁在吃内存十有八九是某个Python进程留下了僵尸对象或者日志缓冲。top/htop动态查看系统资源。htop可读性更好还能直接按F5切换树状视图看清父子进程关系。服务器上没装就装一个属于用了就回不去的工具。lsof -i :8000查看8000端口被哪个进程占用。启动服务提示Address already in use的时候用这条命令找到占用进程再决定是kill它还是换端口。这里必须提醒一句ps aux看到的结果里除了你的服务进程还会有一些系统进程别一看到带python的进程就kill -9先确认清楚。我曾经在一次事故中看到好几个python相关进程想着全杀掉结果把别人的Jupyter服务也给停了场面一度很尴尬。4.2 后台运行与守护服务用python3 app.py直接跑服务SSH断开进程就没了这在生产环境里完全不可接受。正确姿势是让服务脱离终端独立运行。nohup python3 app.py app.log 21 nohup忽略挂断信号放入后台日志重定向到文件。这是最简单的后台运行方式适合临时任务、跑一次性脚本。nohup配合echo $!命令执行后立刻用echo $!打印出新进程的PID记下来后续kill就靠它。如果你已经忘了进程PID用pgrep -f app.py直接按名字查实际使用中比我ps再grep方便一些。有一种情况要特别小心nohup启动的进程如果服务器重启它不会自动恢复。你需要在系统启动时手动拉起或者写成开机脚本。这也是为什么现在比较规范的做法是使用systemd下一节细说。4.3 用systemd管理Python服务真实的生产项目里我强烈建议用systemd来管理Python服务。它天然支持开机自启、崩溃自动重启、日志集中管理比nohup可靠得多。只需要写一个service文件。先看一个典型的service文件长什么样比如/etc/systemd/system/myapp.service[Unit] DescriptionMy Python Application Afternetwork.target [Service] Userwww WorkingDirectory/srv/myapp ExecStart/srv/myapp/.venv/bin/python /srv/myapp/app.py Restartalways RestartSec3 EnvironmentPYTHONUNBUFFERED1 [Install] WantedBymulti-user.target几个关键字段值得展开说ExecStart启动命令。注意这里用的是虚拟环境里的Python解释器完整路径不要写python否则系统可能找不到。Restartalways只要进程退出就自动重启不管退出码是什么。配合RestartSec3设置重启间隔防止崩溃-重启-再崩溃的死循环把机器搞挂。Environment可以设置环境变量在这里放PYTHONUNBUFFERED1避免输出缓冲方便看日志。写好后执行systemctl daemon-reload systemctl enable --now myapp systemctl status myapp journalctl -u myapp -fjournalctl -u myapp -f是查看服务日志的命令-f实时跟随这样你的tail -f基本就被它替代了。踩过一次坑service文件里ExecStart写成了相对路径结果服务起不来报Exec format error。查了好一会儿才发现systemd要求必须是绝对路径这个细节记得划重点。5. 网络排查与连接调试接口不通时快速定位5.1 端口连通性与连接检查开发调试时本地服务接口能通但一到服务器上就说Connection refused、Timeout这类问题几乎每个Python开发者都遇到过。排查的顺序和工具有讲究。先分清楚问题在哪一层。最简单的验证工具是ping它检查三层网络通不通。但如果ping通而接口还是连不上问题多半出在端口层面。telnet 127.0.0.1 8000检查本机8000端口是否开放。如果端口通了你会看到连接成功的提示甚至进入一个空命令行界面按Ctrl ]再输入quit退出。如果看到Connection refused说明服务没监听这个端口或者端口被防火墙挡了。ping -c 4 目标IP发4个包测试基本连通性判断是服务器宕机还是网络隔离。ss -tlnp | grep 8000查看监听端口和对应进程。用netstat -plant也行不过现在很多新系统里ss是默认推荐的输出也更清晰。curl -v http://127.0.0.1:8000/health如果服务有健康检查接口这是最快的自测方式。看到Connected to 127.0.0.1 port 8000说明TCP层通了再看HTTP层返回内容。综合使用口诀是先ping看网络通不通再telnet或ss看端口有没有在听最后curl看应用层给出的响应。按这个顺序一步步缩小范围基本能定位绝大多数网络故障。5.2 curl接口调试的瑞士军刀curl对于Python开发者来说价值等同Postman但更高效因为你在终端里就能完成HTTP请求还能直接管道交给jq解析。curl -I https://example.com只拿响应头快速确认服务活着、状态码对不对。curl -X POST -H Content-Type: application/json -d {name:test} http://127.0.0.1:8000/api/usersPOST一个JSON请求调试自己写的FastAPI或Flask接口再合适不过。curl -o /dev/null -s -w %{http_code} %{time_total}\n https://example.com只看响应状态码和总耗时压测接口响应时间的时候好用。curl http://127.0.0.1:8000/api/users?page1size20注意URL带参数时整个字符串用双引号包住避免被shell转义。这个坑很多人碰到过请求发出去服务端收到的参数数量不对很可能就是少了引号。我个人习惯是在调试接口时把curl和jq串起来用curl -s http://127.0.0.1:8000/api/users | jq .data[0]一行命令直接看到结构化数据不用把原始返回抄到编辑器里另做格式化。5.3 常用排查命令一句话速查整理一份我自己放在笔记里的速查表按场景区分方便你遇到问题时快速找到入口场景命令说明网络基本连通性ping -c 4 目标IP发4个包判断三层通不通端口是否开放telnet 127.0.0.1 8000不通会提示Connection refused或timeout端口监听与进程ss -tlnp | grep 8000看到PID和程序名定位谁在占用HTTP自测curl -v http://127.0.0.1:8000/health查看HTTP/1.1响应细节动态服务日志journalctl -u myapp -fsystemd服务的日志跟随检查磁盘df -h磁盘空间不足时服务会写不了日志症状千奇百怪查看目录体积du -sh *找出哪个目录把磁盘吃满了补充一个容易忽略的点排查问题很多时候是数据库、Redis连不上而不是HTTP问题。这时候先确认外部的中间件服务是不是活着再检查Python进程和它们的网络连通性。别一上来就质疑自己的代码先把环境层面理清楚。6. 常见问题速查表报错时先查这份清单这一节把Python和Linux配合使用时最典型的报错整理成表格每一条都是实际运维中反复出现的给出方向和初步排查命令。报错/现象常见原因排查命令与思路command not found: python3系统未安装Python或路径没配置检查which python3、ls /usr/bin/python3*用包管理器安装ModuleNotFoundError: No module named requests未激活虚拟环境或包没装pip list看有没有这个包which pip看当前环境再pip installPermission denied文件没有执行权限或目录不可写ls -l 文件名检查权限chmod x 脚本加执行权限Address already in use端口被其他进程占用lsof -i :8000找到进程确认后kill或换端口bash: activate: No such file or directory虚拟环境路径访问错误确认.venv/bin/activate是否正确ls .venv/bin看看结构日志不输出或乱码没设置PYTHONUNBUFFERED或字符集不对加上-u参数设置LANGC.UTF-8重新启动服务启动即退出systemctl status没信息多数是启动命令路径写错或环境变量缺失journalctl -u myapp -e看最近日志重点检查ExecStart路径No space left on device磁盘满了df -h确认空间du -sh *文件删除后内存没释放进程仍持有已删除文件的句柄lsof L1查已删除但被占用的文件重启相关进程表格里的每一条都是我亲眼见过的问题。No space left on device这条值得单独提醒日志文件被删了但Python进程还开着磁盘空间却不降反升因为进程持有文件句柄文件虽然从目录里消失了但空间并没有释放。排查方法就是用lsof L1找出被占用但已无目录链接的文件然后重启进程就好。我再给一个通用建议遇到问题先看日志日志不够再上ps、ss看进程端口最后再用strace这类更底层的工具去追系统调用。不要一上来就改代码那只会让问题更复杂。写到这里其实还能往下延展很多比如性能调优时看的vmstat、iostat容器场景里的docker logs等等。但核心思路是一致的把命令当作解决问题的杠杆而不是背口诀。我个人的体会是真正熟练的标志不是记住多少条命令而是知道在什么场景下选什么工具并且能在一两分钟内完成排查闭环。如果你能把上面这些命令配合场景串起来练习遇到服务器相关问题就不会再慌。
返回列表