做Python开发,很多次被卡住的地方真不是业务逻辑本身。爬虫要部署到服务器定时跑,Django项目要在Linux上重启服务,量化策略想让它夜里不因为断线就停掉——这些场景,Python只负责把业务跑起来,真正让代码在服务器上活下去的,是那一行行Linux命令。我见过不少同事本地开发顺风顺水,一上手生产环境就发懵,日志找不到、进程杀不掉、端口起不来,问题往往就出在Linux命令这一层。
这篇不会像命令大全那样把几百条命令罗列给你,因为列完你也不会去看第二遍。我会围绕Python开发真正高频的场景,把文件目录、进程管理、日志排查、环境管理、远程部署这几块讲透,每条命令都会说明它解决什么问题、背后是什么逻辑、实际部署时有什么坑。无论你是刚开始接触Linux的Python新手,还是已经写了两三年代码但平时很少上服务器的开发者,读下来应该都能直接用得上。
开始之前先讲一个底层认知:Linux命令不是靠背的,靠的是建立“命令行思维”。图形界面里你点几下鼠标完成的事情,命令行里本质上就是你告诉系统一个明确的对象类型和操作路径。先想清楚操作对象是谁、在哪个路径、要做什么,再决定敲哪条命令,这个思路理顺了,下面所有命令都会被串起来。
1. 文件与目录操作:Python项目落地的第一道门槛
任何一个Python项目落到服务器上,第一步基本都一样:把代码放进指定目录,规划好虚拟环境和日志位置。本地IDE把所有文件操作都封装了,到了纯命令行的服务器环境,这些操作全都得自己来。这里最让人心里打鼓的往往就是删除操作,尤其是那条rm -rf。
1.1 创建、复制、移动与删除:先确认再动手
最常用的创建命令是mkdir,加-p参数可以一次创建多级目录。mkdir -p /data/www/myblog/logs这条命令,即使logs的上级目录都不存在,也会一次性全建出来,省得一级一级mkdir。创建空文件用touch,平时用得不多,但调试时想快速生成临时占位文件或者更新文件时间戳时非常顺手。还有一个容易被忽略的细节:创建目录后一定用ls -lah确认一下权限和路径,别等到后面写日志才发现目录权限不对。
复制和移动是高频操作。cp -r source_dir target_dir能递归复制整个目录,少写这个-r,cp会直接报cannot copy a directory。mv同时承担移动和重命名两个职能,同目录下执行mv其实就是在改名;跨文件系统移动时mv会先拷贝再删除,大目录速度会偏慢,这属于正常现象。我处理项目目录时有个习惯,目录迁移前先tar打包再解压,比直接cp或mv快,还能顺便做一次备份。
删除是重灾区。rm -rf的威力,很多人是在生产环境用惨痛教训记住的。我的规矩是:删除前先跑一次ls确认目标路径,路径按Tab补全后再看一遍,确认无误才回车。更稳妥的做法是先mv到一个临时目录,比如mv suspicious_dir /tmp/trash_$(date +%s),观察几天确认没有影响再真正删除。这一招救过我两次,有一次是把某个服务目录整个搬走,第二天发现管理后台一直在报错,因为有个进程还在读旧路径,如果没有临时目录兜底,删掉就彻底找不回来了。
顺便给刚从Windows切过来的朋友一个对照表,这套对应关系对理解命令行操作很友好:
| Windows习惯 | Linux对应命令 | 说明 |
|---|---|---|
| 打开文件夹 | cd /path/to/dir | 切换工作目录 |
| 查看文件夹内容 | ls -lah | 含权限、大小、隐藏文件 |
| 新建文件夹 | mkdir -p path | 递归创建 |
| 复制文件 | cp file target | 复制单文件 |
| 复制整个文件夹 | cp -r dir target | 递归复制 |
| 删除文件夹 | rm -rf dir | 危险,务必先确认路径 |
| 重命名/移动 | mv old new | 同目录下是重命名 |
表格里ls -lah的-a参数尤其值得强调,不加它你看不到.env、.venv这类隐藏文件,而Python项目的隐藏文件往往是出问题最多的地方。还有一点必须记住:服务器上没有Windows那套回收站概念,rm -rf之后没有撤销,这条要刻在脑子里。
1.2 find与grep:在海量文件里精准命中目标
项目目录跑了几个月以后,依赖、缓存、日志、临时文件全混在一起。想定位一个具体文件用find,想定位文件里的具体内容用grep,这两个命令组合是文件层面的“搜索双雄”。
find的常用姿势有这么几个。按文件名定位:find /data/project -name ".py",能把目录下所有Python文件列出来。按类型定位:find . -type d -name "pycache",找出所有缓存目录,配合-delete参数可以直接清掉。按大小定位:find /var/log -type f -size +100M,排查磁盘占用时一条命令就能揪出大文件。还有一个容易忽略的参数-mtime,比如find . -name ".log" -mtime +7,找出7天前修改的日志文件,配合清理脚本就能实现日志的自动滚动。
grep在Python项目里我最常用的场景有两个。一个是找残留调试代码,grep -rn "print(" --include="*.py" src/,找出所有保留的print输出,-n显示行号、-r递归搜索、--include限定文件类型。另一个是根据报错定位代码位置,线上日志抛了一个异常,grep -rn "SomeError" src/,能立刻定位到定义和调用处,比在服务器上打开编辑器硬翻快得多。注意find搜的是文件名,grep搜的是文件内容,刚接触的人容易把两者搞混。在大目录里全局grep -r会很慢,建议先用find把目录范围缩小再检索,效率能提升一个量级。
1.3 压缩与解压:打包迁移代码的固定动作
把代码从本机搬到服务器,或者给整个项目做备份,压缩解压都是绕不开的。Python项目最常碰到的格式是tar.gz,一条tar -czvf project.tar.gz /data/project就把整个目录打包压缩。对应的解压命令是tar -xzvf project.tar.gz,如果下载的包只是.tar没有.gz,把-z去掉即可。
很多人会遇到tar: Error is not recoverable: exiting now,也就是网上常搜的“tar包解压命令status 1”。我排查这类问题有一个固定顺序:先看第一条错误信息,通常它会直接告诉你文件格式不对、权限不足还是文件缺失;然后校验文件大小,很多情况是下载不完整导致的;最后确认目标目录是否有写权限,尤其是解压到系统目录时。盲目重新解压解决不了问题,先定位原因才是正路。
解压之前还有一个好习惯:tar -tzvf project.tar.gz先查看包内文件列表,避免解包后文件散落一地。打包的时候,路径末尾的斜杠也有讲究,tar -czvf a.tar.gz /data/project/和tar -czvf a.tar.gz /data/project解出来的目录结构不同,一个包含最外层project目录,一个可能把内容直接解到当前目录。有些精简版Linux系统里没有tar命令,装一个就好,Debian系用apt install tar,RedHat系用yum install tar;或者改用zip/unzip,功能和通用性也不差。
2. 进程管理:让Python脚本按你的意愿活着和死去
本地运行Python脚本,Ctrl+C就能停,窗口一关进程就没了。服务器上完全是另一套逻辑:服务要长时间跑,SSH会话断开后进程还得在后台继续工作,出问题时要在几十个进程里准确找到自己的目标,然后干净利落地结束它。这一章把查进程、杀进程、常驻进程这条完整链路讲清楚。
2.1 ps、pgrep、top:先找到目标进程再说别的
管理进程的第一步是“看到”进程。ps aux列出所有进程的最全信息,包括用户、PID、CPU和内存占用、启动命令行。跟Python相关的进程通常显示为python3或python,过滤用的组合是ps aux | grep python3。如果服务器上跑着多个Python服务,想匹配特定那个,用ps aux | grep "app.py"按完整命令行过滤。
这里有一个每个新手都会遇到的坑:ps aux | grep python3的输出里,总会混入一条你自己的grep命令,因为它的命令行里也包含python3。很多人用grep -v grep来做排除,但在脚本里这种写法并不健壮。更干净的做法是直接用pgrep -af python3,按进程名和命令行匹配并直接输出PID和完整命令行,一步到位。比如pgrep -af "python manage.py runserver"就能确认想找的进程到底是不是那一个,避免误打误撞。
看资源占用别只看ps的瞬间值,因为两次采样之间CPU波动完全看不出来,这时用top。top实时刷新展示资源占用排行,按P按CPU排序、按M按内存排序,服务器资源告警时先开top看是CPU还是内存爆掉,再顺藤摸瓜找到对应进程。装了htop体验更好,方向键选中进程、F9发信号,效率明显提升。一个建议是:先top定位,再pgrep确认,最后再决定怎么处理,这个顺序比较规范。
2.2 kill与信号:优雅退出优先,SIGKILL兜底
找到PID之后,接着就是怎么结束它。很多新手上来就kill -9 PID,这样确实能达到目的,但会跳过程序的清理逻辑,比如数据库连接没释放、临时文件没删干净、状态没保存。更合理的方式是先执行kill PID,默认发送SIGTERM(15号信号),相当于通知程序“准备一下再退出”。Python代码里可以通过signal模块注册SIGTERM处理器,在退出前做资源清理。等几秒看进程还在不在,还赖着不走再kill -9(SIGKILL)强杀。这套“先商量后动手”的顺序,对你自己的服务是一种保护。
批量结束多个同名进程时,用killall python3或pkill -f app.py。pkill强大之处在于支持正则匹配命令行,但也正因如此容易误杀,比如pkill -f python会把所有命令行里带python的进程全干掉,包括别的项目的定时任务。我吃过一次亏,就是在一台共享开发机上执行了类似命令,把同事跑了一晚上的训练脚本给结束了。后来我给自己立了规矩:先用pgrep -af列出匹配结果,确认匹配对象,再kill一个个具体的PID,绝不贪图一条命令的爽快。
杀进程时还会碰到权限问题,杀掉别人启动的进程会提示Operation not permitted,要么找管理员,要么确认这是你自己的进程。另外,如果kill之后进程迟迟不消失,很可能是进入了不可中断的睡眠状态,比如卡在磁盘IO上,这种时候kill -9也未必立刻生效,强行杀的风险也不小,只能等IO恢复或重启机器。区分这些情况,对线上容错非常有帮助。
2.3 nohup、screen、systemd:让Python服务常驻后台
本地开发时,Ctrl+C停掉接口服务很正常,但生产环境的要求是:终端会话断开后,服务必须继续跑。面向这种常驻需求,我按项目复杂度分三档处理:nohup、screen、systemd。
最轻量的是nohup。nohup python app.py > app.log 2>&1 &,这行命令的意思是让程序忽略挂断信号、标准输出和错误都写入app.log、放到后台运行。最后那个&不能省,少了它命令还是前台阻塞。执行完可以把SSH连接直接关掉,程序照常在跑,日志随时用tail -f app.log查看。nohup适合快速启动和临时性的后台任务,缺点是进程管理比较粗放,没有做守护和自动重启。
screen是会话级的常驻方案。screen -S mytask开一个独立会话,在里面跑Python脚本,然后按Ctrl+A再按D把会话放到后台,这个过程叫detach。关键在于:SSH断线之后,screen里的进程照样运行;下次连上来,screen -r mytask就能回到那个会话继续看输出。这个特性对长时间任务太有用,比如批量爬虫和数据清洗,跑一天一夜都安心。screen -ls可以查看所有会话,任务跑完用screen -S mytask -X quit关闭会话。要是同时跑多个任务,多开几个screen会话互不干扰。
如果服务需要开机自启、崩溃自动拉起,那就要上systemd。写一个.service文件,指定ExecStart和Restart策略,比如Restart=on-failure,进程异常退出后自动拉起。虽然配置它需要一点学习成本,但对长期运营的线上服务来说,这是我最推荐的方式。经验判断是:任务只跑一两个小时用nohup或screen足够,没必要配systemd;真正长期提供服务的那类,一开始就应该用systemd管起来,别让服务裸奔。
3. 日志与文本处理:线上排错的关键技能
代码能跑通不代表能顺利上线,线上问题排查几乎全靠日志。日志文件动辄几十MB甚至几个GB,用编辑器打开根本不现实,这时候真正起作用的是tail、less、grep、awk、sed这组命令。掌握它们,你在服务器上排错的速度会明显提升一个档次。
3.1 tail与less:日志永远在实时刷新
查看日志时我使用频率最高的是tail -f app.log,-f表示follow,实时跟进文件新增内容。部署新版本后,开一个终端窗口tail -f盯着,看到Application startup complete之类标志才开始收工;线上有人反馈接口挂了,也开tail -f实时盯,一边让用户复现一边观察错误日志,问题定位往往几分钟内完成。
只想看最近N行,用tail -n 200 app.log,进程刚启动崩溃时,最近200行往往就是异常栈核心。还有两个实用的配合:一是日志轮转后要tail -f对的文件,别盯错了历史包;二是tail -f app.log | grep ERROR,只实时过滤错误级日志,把海量噪音降下来。这条管道我几乎每天都会用。
如果要在已经很大的日志里翻找历史记录,less比tail好用。less app.log进入分页模式,按G到文件末尾、按g回开头、按/输入关键字搜索并回车跳转、按n继续找下一处、按q退出。less是按需加载内容的,处理几百MB日志不会像cat那样一次性灌满内存导致卡顿。三个命令的定位很清晰:查看小文件用cat,翻阅大文件用less,实时监控用tail -f,各司其职,别混用。
3.2 grep、awk、sed:从日志里提炼出有用信息
grep不只是用来找代码,它更擅长从日志里抽取某类记录。比如查某个接口的全部请求:grep "/api/orders" access.log;统计500错误行数:grep -c "500" access.log;-c统计行数、-o按匹配输出、-v反向排除,结合起来可以做不少简单的日志分析。日志量特别大时,先grep筛一遍再对结果做后续处理,避免在几GB文件上做无谓的完整扫描。
awk是提取字段的神器。最常见的日志格式是用空格分隔,比如访问日志可能是“IP 时间 路径 状态码 响应时间”,想统计某个接口的请求来源IP,用awk '/"/api/orders"/ {print $1}' access.log | sort | uniq -c | sort -rn,一条管道命令就完成了分组统计。这段表达式里awk提取第一列、sort排序、uniq -c统计出现次数、sort -rn按数量倒序排列,是日志分析的经典组合,建议直接背下来。注意awk默认按空格和Tab切分字段,$1是第一列、$NF是最后一列,只要日志字段顺序一变,数字就得跟着调整。
sed主要负责文本替换和流式编辑。比如日志脱敏,把日志中的手机号中间四位打码:sed -E 's/([0-9]{3})[0-9]{4}([0-9]{4})/\1****\2/' app.log。批量改Python源码也很常用,把旧接口名批量改成新接口名:sed -i 's/old_api/new_api/g' src/*.py。这里有一条必须警惕:-i参数是直接修改文件,改错没有撤销,所以执行带-i的命令前一定先备份,或者先跑一遍不带-i的版本在终端看替换结果。
4. Python环境管理:一劳永逸地解决版本冲突
换了新服务器、迁移了一次项目之后,很多人会开始认真对待Python环境管理。同一台机器上可能同时存在Python 3.8、3.10、系统自带版本、项目独享虚拟环境,版本错乱导致的依赖冲突非常磨人。这一章聊环境管理的常用命令和我的选择逻辑。
4.1 venv与conda:按场景选择虚拟环境
venv是Python官方自带的虚拟环境方案,用法很固定:python3 -m venv .venv创建,source .venv/bin/activate激活,然后直接在环境里pip install,不会污染系统Python。项目根目录会生成一个独立的.venv目录,里面有一套独立的解释器和pip,把这个目录删掉就等于彻底卸载环境,干净利落。在服务器上换了机器,我可以先跑一句python3 -c "print(abs(-5))"快速验证解释器是否正常,再进环境跑业务,这个小验证我每次都顺手做一遍。
conda适合数据科学项目,尤其是需要指定Python小版本的项目。conda create -n myenv python=3.10创建指定版本环境,conda activate myenv切换环境。conda还能管理一些非Python的系统级依赖,比如科学计算库的底层二进制库,省去不少编译烦恼。缺点是环境体积偏大,离线迁移也不如venv直接。我现在的选择原则是:纯后端、爬虫这类业务项目用venv;涉及numpy、pandas、scikit-learn这类重依赖的项目用conda,因为二进制依赖的解决更省心。
很多人踩过这样的坑:直接往系统Python里pip install,装了一堆包之后版本互相打架。建议所有项目一律在虚拟环境里操作,至少也加个--user。判断当前是否在虚拟环境里,用which python3,路径里带.venv字样就对了。
4.2 服务器上安装Python:包管理器与源码编译两种路径
新买的云服务器通常自带一个Python 3,可版本往往偏旧,想用新版本就得自己装。最快的路径是包管理器:Debian系用sudo apt update && sudo apt install python3 python3-venv python3-pip,RedHat系用sudo yum install python3。这样装的是系统源里的版本,不一定最新,但依赖关系自动处理好,胜在省心。
要装某个指定小版本,比如Python 3.11,推荐从python官网下载源码编译安装。流程固定:wget下载源码包,tar解压,进入目录后./configure --prefix=/usr/local/python311,然后make -j$(nproc)和make install。装完解释器在/usr/local/python311/bin/python3.11,再用ln -s /usr/local/python311/bin/python3.11 /usr/local/bin/python3.11做一个软链,全局就能直接访问。源码编译前必须确保装了gcc、make和zlib等开发库,否则编译到一半报错,排查起来相当耗时。系统里装了多个Python版本后,用update-alternatives可以配置默认python3指向哪个版本,省得每次敲完整路径。
4.3 环境变量与项目依赖导出:换个环境不迷路
环境装好后,还要学会管理环境变量。敏感配置比如数据库地址、API密钥,不应该硬编码进Python源码,而是通过环境变量注入。临时设置用export DB_HOST=127.0.0.1,只在当前shell会话内生效;想永久生效,把export行写进~/.bashrc或~/.zshrc,执行source ~/.bashrc加载。Python代码里用os.environ.get("DB_HOST")读取,这套模式在Django和爬虫项目里都很常见。
换机器部署时,导出依赖是标准动作:在虚拟环境里执行pip freeze > requirements.txt,把所有包和版本号记录下来;新机器上pip install -r requirements.txt一键还原。如果项目依赖中间升级过,requirements.txt里可能会出现一些多余的包,用pipreqs按项目实际import生成更干净:pip install pipreqs && pipreqs ./ --force。另外我习惯给备份文件名自动打日期,命令是tar -czvf project_$(date +%Y%m%d).tar.gz /data/project,配合date命令做日志轮转和每日备份,比手动输入日期可靠得多。
5. 网络与远程部署:把代码真正送上服务器
本地代码写得再好,最终也要部署到服务器上跑起来。Python开发者最常打交道的远程操作集中在登录、传输、接口调试和端口排查这四块,熟练了之后,部署流程基本就顺畅了。
5.1 ssh、scp、rsync:登录传输备份的三件套
远程登录的基础是ssh user@server_ip。用密码登录可以,但每次输入很烦,安全上也弱一些。我建议配一次SSH密钥:本地ssh-keygen -t ed25519生成密钥对,把公钥用ssh-copy-id user@server_ip推送到服务器,之后登录免密。在~/.ssh/config里给服务器配置别名后,日常登录就只剩ssh myserver这一下,多台服务器管理会很省心。顺手提一句,现在不少开发者喜欢用VSCode的Remote-SSH插件直接在服务器上写代码,服务器端只要SSH正常,前面说的这些命令依然一样都省不掉。
文件传输用scp。上传:scp local_file user@server:/data/project/;下载整个文件夹:scp -r user@server:/data/project /local/backup/。很多人搜“sz命令下载整个文件夹”,这里得解释一下:sz命令来自lrzsz工具包,走ZModem协议,一般只能传单个文件,想在终端里下载整个文件夹,要么先打包,要么直接用scp -r或rsync。我的首选是rsync:rsync -avz --progress user@server:/data/project/ /local/backup/,-a归档保留权限和软链、-v输出详情、-z压缩传输。rsync最大的优势是增量同步,多次同步只传变化的部分,做定期备份和部署尤其合适,比scp省流量得多。注意如果服务器只允许密钥登录,不管scp还是rsync都要先把密钥配置好,否则就白忙。
5.2 curl与wget:接口调试和资源下载的好帮手
调试HTTP接口,服务器上不一定有Postman,但一定有curl。检查一个GET接口通不通:curl -I http://127.0.0.1:8000/api/,看响应头里的状态码,200正常、405方法不匹配、500说明服务内部报错。发一个POST请求:curl -X POST http://127.0.0.1:8000/api/orders -H "Content-Type: application/json" -d '{"order_id":123}',加上-v参数能看到完整请求报文和响应报文,排查参数错误、鉴权失败这类问题非常直观。
wget更像一个专职下载器。wget https://xxx/python.tar.gz把文件拉到当前目录,加-c支持断点续传,下载大文件中断后可以接着下;加-b参数放后台下载并写日志,适合网络不太稳定的环境。之前提到的编译安装Python源码,就经常用wget下源码包再tar解压。粗略理解就是:curl功能全面,适合调协议;wget专精下载,适合拿文件。两者配合,日常网络操作基本不缺工具。
5.3 端口与连接排查:为什么8000端口起不来
线上部署最常见的报错之一是Address already in use,两个服务抢同一个端口,或者上次的服务没有退出干净。排查端口的命令是ss -tlnp或netstat -tlnp,-t显示TCP、-l显示监听、-p显示进程、-n不做域名解析。输出里找到8000端口,最后一列就是PID和进程名,比如python3(PID 12345),确认后kill 12345就能释放端口。新的Linux发行版都有ss,老的系统可能只有netstat,两者都会用总能应付。
还有一种很诡异的情况:本地服务工作正常,但外部客户端连不上。我会按固定顺序排查:先lsof -i:8000确认进程确实在监听;再看监听地址是0.0.0.0还是127.0.0.1,后者外部当然连不上;接着检查防火墙规则有没有放行;最后看云服务商安全组。绝大多数的“端口连接不上”,按照进程在不在、监听地址对不对、防火墙放行没放行、安全组规则是否允许这个顺序走一遍,都能定位到原因。
数据库层面的命令行连接也值得掌握。比如有些Python项目需要连微软的SQL Server,在Linux服务器上安装sqlcmd之后,用sqlcmd -S 127.0.0.1 -U sa -P '你的密码'登录,成功后再执行SELECT name FROM sys.databases;就能列出服务器上所有数据库的名字,查库备份看表结构都能在命令行里完成,不用每次都打开图形客户端。这个场景对接老系统时经常遇到,会了很省事。
6. 高频场景命令速查:拿来就能用
前面几章是按主题拆解的,这里我整理了一张速查表,把Python开发实际工作中最高频的场景和命令对应起来。建议先收藏,需要时查一查,用熟了之后很多命令会变成肌肉记忆。
6.1 Python开发高频场景速查表
| 场景 | 常用命令 | 关键说明 |
|---|---|---|
| 删除整个文件夹 | rm -rf /path/to/dir | 危险,先ls确认 |
| 递归查找Python文件 | find . -name "*.py" | 先用find缩小范围 |
| 检查Python版本 | which python3 && python3 --version | 确认是否在虚拟环境 |
| 创建并激活虚拟环境 | python3 -m venv .venv && source .venv/bin/activate | 项目内执行 |
| 导出依赖清单 | pip freeze > requirements.txt | 在虚拟环境内执行 |
| 查看Python进程 | pgrep -af python3 | 带完整命令行输出 |
| 杀掉指定进程 | kill -9 PID 或 pkill -f app.py | 优先用默认kill |
| 后台常驻运行 | nohup python app.py > app.log 2>&1 & | 末尾&不可省 |
| 创建分离会话 | screen -S mysession | 恢复用screen -r |
| 实时跟踪日志 | tail -f app.log | 配合grep过滤 |
| 翻阅大文件 | less app.log | G到末尾,/搜索 |
| 统计错误行数 | grep -c "ERROR" app.log | 快速数量统计 |
| 提取日志字段 | awk '{print $1}' app.log | 结合sort/uniq |
| 批量替换文本 | sed -i 's/old/new/g' file | 先预览后-i |
| 上传文件到服务器 | scp file user@server:/path | 递归加-r |
| 增量同步目录 | rsync -avz user@server:/src /dst | 增量备份神器 |
| 调试GET接口 | curl -I http://127.0.0.1:8000/api | 看状态码 |
| 调试POST接口 | curl -X POST -H "Content-Type: application/json" -d '{}' URL | 用-v看细节 |
| 查看端口占用 | ss -tlnp | 找到PID并kill |
| 文件名加日期 | mv app.log app.log.$(date +%Y%m%d) | 日志轮转常用 |
| 登录MS SQL Server | sqlcmd -S 127.0.0.1 -U sa -P '密码' | 执行SELECT name FROM sys.databases;查看库列表 |
6.2 我踩过的几个经典坑
搜热词进来的朋友,多半也和我一样是带着问题来的。这些坑我都亲身踩过,有的甚至是在线上翻过车的,整理出来供你避雷。
第一个坑是grep过滤自己。ps aux | grep python时,grep命令自身也会出现在结果里,因为命令行里包含python这个词。单纯看看还好,如果写脚本去解析列表再kill,很可能把自己的运维脚本一起干掉。我现在一律用pgrep -af替代这个组合,输出干净,也不用额外排除。
第二个坑是路径里的空格和特殊字符。用scp、tar处理目录时,路径有空格必须加引号或转义。打包路径末尾的斜杠也很微妙,前面说过,它决定了解压之后是带着最外层目录还是直接把内容摊在目标目录。解包前不确定就先用tar -tzvf看列表,心里有数再解,能避免文件散落一地。
第三个坑是换行符。在Windows上写的.sh脚本或请求文件传到Linux执行,可能报错“$‘\r’: command not found”。原因是Windows换行是\r\n,Linux只认\n,多出来的\r被当成了命令内容。解决办法是去掉\r:sed -i 's/\r$//' script.sh,或者直接装上dos2unix处理。这个坑几乎每个从Windows切换过来的Python开发者都会遇到一次。
第四个坑是乱杀Python进程。pkill -f python会把命令行里带python的所有进程全干掉,包括别人正在跑的任务。我后来给自己立了规矩:先pgrep -af列出匹配列表,确认无误再用kill加具体PID,宁可多敲几行命令,也不拿业务的可靠性去赌。
第五个坑是环境变量不生效。改完.bashrc忘了source,新开SSH会话找不到刚配置的命令或PYTHONPATH,白查半天。记住source ~/.bashrc这一步,很多环境类问题会瞬间消失。
第六个坑是系统里没有tar。最小化安装或者精简镜像里确实可能只有zip没有tar,装一个就行;或者干脆改用zip/unzip实现同等需求。处理这类问题时先确认环境有什么工具,别一门心思硬套tar。
最后分享一个常用的组合技巧:服务器上跑爬虫或量化策略,我习惯用screen开一个会话,在会话里执行nohup python run.py启动,然后Ctrl+A+D把会话丢到后台。这样程序不会因为SSH断线而退出,我还能随时screen -r回来看看执行进度。如果有多份数据任务需要并行处理,配合xargs -P可以让wget或scp同时处理多个文件,省时间非常明显。如果是每天要定时跑的任务,用crontab挂一个条目,把Linux命令写进Shell脚本自动执行,比如0 6 * * * cd /data/project && .venv/bin/python run.py >> run.log 2>&1,这一套组合基本能覆盖绝大多数Python服务的日常运维需求。
我个人实际操作里的体会是:命令背得再多,不如在真实服务器上把部署流程完整走十遍,踩过的坑才真正是自己的东西。希望这篇整理能帮你少走一些弯路,也欢迎在评论区交流你在生产环境中踩过的其他坑。