日常實(shí)用腳本:從整理分類到自動化部署的完整實(shí)踐指南)
1. 100個(gè)日常實(shí)用腳本一次徹底的工具箱整理先說說我為什么會對“100個(gè)日常實(shí)用腳本”這個(gè)題目感興趣。做了幾年開發(fā)和運(yùn)維電腦里的腳本從零零散撒十幾個(gè)慢慢堆到上百個(gè)散落在各種目錄、甚至聊天記錄里。真正遇到問題時(shí)常常是“好像寫過類似的東西但找不到、也記不清怎么用了”。后來痛定思痛花了一個(gè)周末把所有腳本撈出來重新分類、梳理、補(bǔ)齊參數(shù)和文檔整理成了100個(gè)工具的集合才敢說“日常實(shí)用”這四個(gè)字。這篇內(nèi)容不是教你把100個(gè)腳本從頭寫一遍那沒有意義。我想分享的是這100個(gè)腳本是怎么選出來的、內(nèi)部如何分類組織每一類里核心腳本的設(shè)計(jì)邏輯和關(guān)鍵代碼片段以及部署到真實(shí)環(huán)境時(shí)的完整流程和踩坑記錄。適合三類人看剛?cè)腴T、想通過大量例子提升腳本能力的開發(fā)者手里腳本不少但亂成一團(tuán)、想系統(tǒng)整理的老手以及想在公司或團(tuán)隊(duì)里推廣標(biāo)準(zhǔn)化工具集的負(fù)責(zé)人。內(nèi)容我盡量用大白話講清楚偶爾上點(diǎn)代碼保證你能直接照抄。2. 腳本體系怎么搭先想清楚再動手2.1 什么才算“日常實(shí)用”三條過濾標(biāo)準(zhǔn)100個(gè)腳本聽起來很多實(shí)際上篩選過程非??量?。我從最初200多個(gè)候選腳本里砍掉一半才湊出“這100個(gè)值得留”的清單。篩選標(biāo)準(zhǔn)就三條分享給你參考至少被真實(shí)使用過三次以上。一次性腳本哪怕再精巧除非它解決了某個(gè)高頻痛點(diǎn)否則直接刪掉。判斷依據(jù)很簡單翻歷史記錄同一個(gè)腳本是否反復(fù)出現(xiàn)。單次運(yùn)行時(shí)間不超過幾分鐘。日常工具腳本跑了十分鐘還沒出結(jié)果大部分人就沒有耐心等第二次了。處理大數(shù)據(jù)量的任務(wù)寧可拆成多個(gè)小腳本階段緩存也不要硬扛。不需要復(fù)雜的交互和人工干預(yù)。參數(shù)越少越好能默認(rèn)就不用指定能自動檢測就不讓用戶輸入。命令行工具最怕的就是“你要先告訴我A再告訴我B”時(shí)間長了連作者本人都會忘。拿文件批量重命名舉例我早期版本要求輸入目錄、輸入規(guī)則、輸出格式三個(gè)參數(shù)缺一不可結(jié)果用了兩次就被自己棄了。后來改成默認(rèn)處理當(dāng)前目錄、默認(rèn)規(guī)則是“文件名里的空格替換成下劃線”想自定義再傳參數(shù)這才真正沉淀下來。2.2 整體目錄結(jié)構(gòu)按任務(wù)類型而不是按語言劃分分類是整理這類集合時(shí)最讓人糾結(jié)的部分。我的建議是按任務(wù)類型分目錄而不是按語言分。很多新手喜歡建立python_scripts/、bash_scripts/這樣的文件夾但真實(shí)使用時(shí)你關(guān)心的永遠(yuǎn)是“我要整理文件”“我要看服務(wù)器狀態(tài)”而不是“我該找Python腳本還是Shell腳本”。我最終確定的頂層結(jié)構(gòu)是這樣的分類目錄覆蓋任務(wù)腳本數(shù)量filesystem/文件批量操作、磁盤空間分析、文件類型統(tǒng)計(jì)16text_processing/日志提取、編碼轉(zhuǎn)換、格式化輸出、正則工具18system_ops/進(jìn)程管理、資源監(jiān)控、定時(shí)巡檢、網(wǎng)絡(luò)檢查14data_processing/CSV處理、JSON校驗(yàn)、Excel讀寫、數(shù)據(jù)庫小工具16office_auto/Word/PDF批量操作、Excel合并、素材整理12network_utils/連通性檢測、端口掃描、HTTP接口探測、DNS查詢8backup_sync/文件同步、增量備份、壓縮歸檔、加密備份9dev_helpers/Git輔助、代碼統(tǒng)計(jì)、環(huán)境變量管理、編碼規(guī)范檢查7合計(jì)100這種結(jié)構(gòu)的優(yōu)越性在長期使用時(shí)特別明顯當(dāng)你想找“批量壓縮圖片”的腳本不會糾結(jié)它該歸到圖片處理還是歸檔工具直接進(jìn)backup_sync/翻一圈或者用統(tǒng)一入口搜關(guān)鍵詞就行。目錄本身就是一套記憶索引。2.3 命名規(guī)范腳本名必須是“動詞對象”整理了100個(gè)腳本后我最大的體悟是給腳本起名決定了它能否被長期復(fù)用。好的腳本名應(yīng)該像命令一樣直接表達(dá)出“這個(gè)工具能干什么”。我的統(tǒng)一規(guī)范是動詞_對象.py或動詞_對象.sh小寫加下劃線不用駝峰。反例早期命名正例整理后命名tool1.pymerge_csv.pyfix.pyrestore_backup.shtest2.pycheck_port.pyfinal_version.pydedup_files.py同時(shí)每個(gè)腳本開頭必須有一段固定的Docstring記錄用途一句話說明、用法示例、依賴模塊、維護(hù)日期。這樣即使三個(gè)月沒碰過某個(gè)腳本看一眼頭部也能快速知道它是干什么的、怎么跑。3. 幾類核心腳本的設(shè)計(jì)與實(shí)現(xiàn)細(xì)節(jié)3.1 文件批量處理類整理下載目錄的實(shí)戰(zhàn)范例文件整理類腳本是我日常使用頻率最高的類別。filesystem/目錄下的核心腳本是organize_downloads.py功能是把亂七八糟的下載目錄按文件擴(kuò)展名自動分類歸檔到不同子目錄。實(shí)現(xiàn)思路是用Python的pathlib遍歷目錄根據(jù)后綴名映射到目標(biāo)類別遇到同名文件自動加序號防止覆蓋。關(guān)鍵代碼只有三四十行但有幾個(gè)細(xì)節(jié)是真正決定成敗的地方from pathlib import Path import shutil import re # 擴(kuò)展名到類別目錄的映射表 CATEGORY_MAP { images: {.jpg, .jpeg, .png, .gif, .bmp, .svg, .webp}, documents: {.pdf, .doc, .docx, .txt, .md, .ppt, .pptx}, sheets: {.xls, .xlsx, .csv, .tsv}, archives: {.zip, .rar, .7z, .tar, .gz}, programs: {.exe, .msi, .dmg, .AppImage}, scripts: {.py, .sh, .js, .go, .c, .cpp}, media: {.mp3, .mp4, .avi, .mov}, } def safe_move(src: Path, dest_dir: Path) - None: dest_dir.mkdir(parentsTrue, exist_okTrue) target dest_dir / src.name # 文件名沖突時(shí)自動加數(shù)字后綴而不是覆蓋 counter 1 while target.exists(): target dest_dir / f{src.stem}_{counter}{src.suffix} counter 1 shutil.move(str(src), str(target))注意兩個(gè)容易忽略的地方一是CATEGORY_MAP用set做后綴名查找因?yàn)閟et的成員判斷是O(1)比列表的in操作快得多文件數(shù)量成百上千時(shí)差距顯著二是while target.exists()循環(huán)必須設(shè)置上限否則一旦遇到極端情況比如文件名全是同一前綴會無限循環(huán)。我實(shí)際就遇到過某個(gè)目錄下有幾千個(gè)相似文件這層保護(hù)讓腳本避免卡死。還有一點(diǎn)經(jīng)驗(yàn)是默認(rèn)先干跑dry-run一遍只打印“將移動哪些文件、移到哪里”不加--execute參數(shù)絕不真正移動文件。這個(gè)習(xí)慣救過我很多次尤其是對照片目錄做整理時(shí)一旦移動錯(cuò)位置恢復(fù)成本極高。3.2 文本與日志處理提取和清洗的邊界問題文本處理類腳本的典型場景是日志提取。text_processing/里的extract_log.py核心功能是從滾動日志中按時(shí)間段和關(guān)鍵字抽取上下文。寫這類腳本最大的難點(diǎn)不是正則本身而是定義“一段日志”的邊界。很多時(shí)候一條日志記錄跨多行比如Python tracebackJava異常堆棧等只按行匹配會截?cái)嚓P(guān)鍵信息。我的做法是先判斷“本行是否是一條日志的新起點(diǎn)”通過時(shí)間戳模式來劃分記錄而不是按固定行數(shù)分割import re from datetime import datetime # 匹配常見日志行首時(shí)間戳如 2025-06-01 10:23:45 TIMESTAMP_RE re.compile(r^(\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})) def extract_slice(log_path, start_time, end_time, keywordNone): start_dt datetime.strptime(start_time, %Y-%m-%d %H:%M:%S) end_dt datetime.strptime(end_time, %Y-%m-%d %H:%M:%S) records [] current [] current_ts None with open(log_path, r, encodingutf-8, errorsreplace) as f: for line in f: m TIMESTAMP_RE.match(line) if m: # 新記錄開始先處理上一條 if current and current_ts is not None: records.append((current_ts, current)) current_ts datetime.strptime(m.group(1), %Y-%m-%d %H:%M:%S) current [line.rstrip()] elif current is not None: # 非時(shí)間戳開頭的行歸屬當(dāng)前記錄 current.append(line.rstrip()) # 按時(shí)間范圍過濾 result [] for ts, lines in records: if start_dt ts end_dt: if keyword is None or any(keyword in l for l in lines): result.append(\n.join(lines)) return \n\n.join(result)實(shí)戰(zhàn)中還有兩個(gè)經(jīng)驗(yàn)日志文件編碼千奇百怪UTF-8帶BOM、GBK混用非常常見。讀取時(shí)用errorsreplace而不是直接報(bào)錯(cuò)退出這樣至少能把內(nèi)容提取出來壞字符后續(xù)再單獨(dú)排查。超大日志不能一次性read()進(jìn)內(nèi)存。幾GB的日志文件一次性讀入內(nèi)存直接卡死必須逐行迭代。上面代碼就是流式處理的模式。3.3 系統(tǒng)巡檢與資源監(jiān)控類定時(shí)巡檢不能只靠手動系統(tǒng)運(yùn)維類腳本最典型的代表是system_ops/system_report.py用于收集服務(wù)器的基礎(chǔ)信息、資源使用率、異常進(jìn)程和磁盤狀態(tài)匯總成可讀報(bào)告。既然要定時(shí)跑輸出格式就必須統(tǒng)一我的做法是直接生成簡單的HTML或Markdown方便后續(xù)通過郵件或其他方式發(fā)送。寫巡檢腳本時(shí)有幾個(gè)細(xì)節(jié)容易踩坑磁盤空間判斷的閾值不能寫死。不同分區(qū)容量差異巨大一個(gè)10GB的分區(qū)用了8GB和1TB的分區(qū)用了800GB完全不是一個(gè)風(fēng)險(xiǎn)等級。用百分比而不是絕對數(shù)值比如超過80%才報(bào)警。CPU使用率的采集需要時(shí)間窗口。讀取一次/proc/stat算出來的只是瞬時(shí)值波動極大。更穩(wěn)妥的做法是間隔幾秒采樣兩次再取差值計(jì)算平均負(fù)載。這也是為什么很多監(jiān)控腳本看著簡單實(shí)際跑起來數(shù)據(jù)卻不準(zhǔn)的原因。腳本核心部分我保留了一個(gè)實(shí)用的進(jìn)程排行邏輯#!/bin/bash # 按CPU和內(nèi)存占用列出Top N進(jìn)程附帶完整命令行 ps aux --sort-%cpu | head -n 15 echo ---內(nèi)存占用Top--- ps aux --sort-%mem | head -n 10 echo ---磁盤分區(qū)使用率--- df -h | awk $NF ! tmpfs {print}df -h的輸出要看懂第一行是文件系統(tǒng)信息重點(diǎn)看“Use%”列和“Mounted on”列。過濾掉tmpfs是為了排除虛擬內(nèi)存文件系統(tǒng)它們占用看著高但實(shí)際不影響物理磁盤。3.4 辦公自動化類報(bào)表合并的高頻場景辦公自動化是“腳本能帶來幸福感”最明顯的一類。office_auto/里最有價(jià)值的是merge_excel.py它能把幾十個(gè)結(jié)構(gòu)相同的Excel表格合并成一個(gè)匯總表然后自動生成匯總統(tǒng)計(jì)。這個(gè)腳本在公司里給行政、財(cái)務(wù)、運(yùn)營同學(xué)解決了不少重復(fù)勞動。實(shí)現(xiàn)上我避免了重型框架直接用Python標(biāo)準(zhǔn)庫加最輕量的方式處理import csv import glob from collections import Counter def merge_report(input_dir./reports, outputmerged.csv): header None all_rows [] for csv_file in sorted(glob.glob(f{input_dir}/*.csv)): with open(csv_file, r, encodingutf-8-sig) as f: reader csv.reader(f) rows list(reader) if not rows: continue if header is None: header rows[0] # 跳過表頭避免重復(fù) all_rows.extend(rows[1:]) # 統(tǒng)計(jì)每一列的出現(xiàn)頻次便于快速核對 if all_rows: col_counter Counter(len(r) for r in all_rows) print(行字段數(shù)分布, dict(col_counter)) with open(output, w, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerow(header or []) writer.writerows(all_rows) print(f合并完成共 {len(all_rows)} 行數(shù)據(jù)輸出至 {output})注意這里讀取用的是utf-8-sig編碼寫入也用utf-8-sig原因在于Excel默認(rèn)用帶BOM的UTF-8識別加了BOM后Excel打開CSV才不會亂碼。很多寫CSV的腳本都栽在這個(gè)細(xì)節(jié)上數(shù)據(jù)本身沒問題但用戶打開看到亂碼第一反應(yīng)就是腳本寫壞了。真實(shí)使用中總體流程比代碼本身重要先把Excel另存為CSV再跑合并腳本得到匯總CSV后可以繼續(xù)交給報(bào)表工具做透視。直接用Python庫去操作xlsx文件當(dāng)然也可以但對十幾MB的大表CSV方案速度遙遙領(lǐng)先而且不容易遇到樣式錯(cuò)亂的問題。3.5 網(wǎng)絡(luò)與連通性工具一鍵診斷勝過到處翻命令網(wǎng)絡(luò)排查類腳本的定位是“把常用命令封裝成好記的工具”。network_utils/check_network.py一次執(zhí)行能輸出本機(jī)IP、默認(rèn)網(wǎng)關(guān)、DNS解析結(jié)果、到目標(biāo)主機(jī)的連通性和延遲、以及開放的常用端口。這里重點(diǎn)說說端口連通性檢測的實(shí)現(xiàn)因?yàn)楹芏嗳酥皇菚胻elnet但腳本自動化時(shí)telnet并不好用import socket def check_port(host, port, timeout3): 檢測TCP端口是否可連通返回(是否成功, 耗時(shí)ms) sock socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(timeout) start time.time() try: result sock.connect_ex((host, port)) elapsed int((time.time() - start) * 1000) return (result 0, elapsed) except socket.gaierror: return (False, -1) # DNS解析失敗 except socket.timeout: return (False, timeout * 1000) finally: sock.close()重點(diǎn)理解connect_ex的返回值0表示連接成功非0值對應(yīng)各種錯(cuò)誤碼。不要用connect()再捕獲異常在批量掃描場景下connect_ex性能表現(xiàn)更好也更便于統(tǒng)一處理。timeout設(shè)3秒對多數(shù)內(nèi)網(wǎng)環(huán)境足夠但長距跨機(jī)房場景需要調(diào)大否則誤報(bào)率高。診斷類腳本還有一條重要原則輸出必須給人看而不是給機(jī)器看。如果能用彩色標(biāo)記連通狀態(tài)就把失敗的項(xiàng)用醒目標(biāo)記展示出來讓人一眼找到問題。一個(gè)“跑完就是一片普通文字”的診斷腳本實(shí)際排查問題時(shí)會加重閱讀負(fù)擔(dān)。4. 部署、調(diào)用與調(diào)度的完整流程4.1 環(huán)境準(zhǔn)備統(tǒng)一解釋器版本和依賴管理100個(gè)腳本分布在多個(gè)目錄必須解決好環(huán)境一致性問題。我最終做法是建立了虛擬環(huán)境并寫了requirements.txt統(tǒng)一管理依賴。Python腳本統(tǒng)一用python3執(zhí)行并且不允許在腳本內(nèi)使用系統(tǒng)Python的第三方庫路徑全部依賴顯式聲明。創(chuàng)建環(huán)境的完整命令序列如下cd ~/scripts python3 -m venv .venv source .venv/bin/activate pip install --upgrade pip cat requirements.txt EOF requests2.32.3 openpyxl3.1.2 pandas2.2.2 PyYAML6.0.2 EOF pip install -r requirements.txt這里刻意鎖了版本號而不是依賴最新版本。日常工具腳本追求穩(wěn)定某天pandas升級到不兼容版本可能導(dǎo)致多個(gè)腳本直接崩潰。萬一后續(xù)有升級需求再主動執(zhí)行pip install --upgrade驗(yàn)證測試。4.2 統(tǒng)一入口讓腳本像命令一樣隨處可調(diào)腳本整理初期我遇到最大的使用障礙是每次都要輸入完整路徑才能執(zhí)行python ~/scripts/filesystem/organize_downloads.py長、容易敲錯(cuò)、還要記得路徑。后來把所有腳本統(tǒng)一暴露給一個(gè)調(diào)度入口run_script.py原理是掃描目錄結(jié)構(gòu)并動態(tài)加載指定腳本通過命令行參數(shù)自動匹配。#!/usr/bin/env python3 import sys import importlib.util from pathlib import Path SCRIPTS_ROOT Path(__file__).parent def find_script(name): # 在所有分類目錄中搜索名稱完全匹配的腳本文件 for py in SCRIPTS_ROOT.rglob(*.py): if py.stem name: return py return None if __name__ __main__: if len(sys.argv) 2: print(用法: python run_script.py 腳本名 [參數(shù)...]) sys.exit(1) script_name sys.argv[1] script_path find_script(script_name) if script_path is None: print(f未找到腳本: {script_name}) sys.exit(1) # 把剩余參數(shù)透傳給目標(biāo)腳本 sys.argv [str(script_path)] sys.argv[2:] spec importlib.util.spec_from_file_location(script_name, script_path) module importlib.util.module_from_spec(spec) spec.loader.exec_module(module)有了這個(gè)入口任意路徑下執(zhí)行python3 ~/scripts/run_script.py organize_downloads --execute即可不用再關(guān)心腳本放在哪個(gè)分類目錄。更進(jìn)一步還可以把入口軟鏈到~/bin/下加入PATH以后直接敲run-script operate_downloads就行。4.3 定時(shí)任務(wù)與日志歸檔自動化是腳本的最終歸宿日常實(shí)用腳本的高頻使用場景是定時(shí)執(zhí)行。我的基本配置方式是Crontab但有三條鐵律腳本內(nèi)必須做日志輸出不能用print看結(jié)果。因?yàn)槎〞r(shí)任務(wù)執(zhí)行時(shí)沒有終端輸出丟了等于白跑。好的實(shí)踐是每個(gè)腳本都支持--log參數(shù)把運(yùn)行記錄寫入固定日志文件。定時(shí)任務(wù)里必須寫絕對路徑。Crontab的環(huán)境變量和交互登錄環(huán)境不同腳本里使用相對路徑極易出錯(cuò)。腳本內(nèi)部涉及路徑的部分統(tǒng)一從環(huán)境變量或配置讀取。給定時(shí)任務(wù)加鎖防止重入。如果腳本處理時(shí)間超過定時(shí)周期上一次還沒跑完下一次就開始了可能造成數(shù)據(jù)錯(cuò)亂。用flock命令做進(jìn)程鎖是最簡單的方案。Crontab配置示例# 每天早上9點(diǎn)執(zhí)行系統(tǒng)巡檢 0 9 * * * cd /home/someone/scripts .venv/bin/python run_script.py system_report --log /var/log/scripts/system_report.log /var/log/scripts/cron.log 21 # 每小時(shí)執(zhí)行一次日志備份帶flock防重入 5 * * * * /usr/bin/flock -n /tmp/backup_sync.lock /home/someone/scripts/run_script.py backup_rotate --log /var/log/scripts/backup_rotate.log 21定時(shí)任務(wù)第一次跑完后務(wù)必人工檢查日志內(nèi)容看輸出是否符合預(yù)期。很多“腳本自動跑了但沒效果”的問題往往就是第一次運(yùn)行時(shí)環(huán)境不對或者路徑錯(cuò)了后續(xù)一直靜默失敗。5. 常見問題與排查技巧實(shí)錄5.1 編碼問題腳本在Windows和Linux間來回搬運(yùn)時(shí)必踩的坑最常見、也最容易讓新手困惑的問題就是編碼不一致。同一份CSV文件在Windows上Excel另存的默認(rèn)編碼是GBK在Linux上常見的UTF-8。寫腳本如果固定用某種編碼讀取必然在一個(gè)平臺報(bào)錯(cuò)。我的排查順序是先file 文件名看系統(tǒng)檢測出的編碼格式再決定用哪種編碼打開。代碼層面讀取文本時(shí)加一層編碼自動探測邏輯def smart_open(path): 自動猜測文件編碼并讀取優(yōu)先UTF-8其次GBK兜底用latin-1 raw open(path, rb).read(4096) if raw.startswith(b\xef\xbb\xbf): return open(path, r, encodingutf-8-sig) try: return open(path, r, encodingutf-8) except UnicodeDecodeError: try: return open(path, r, encodinggbk) except UnicodeDecodeError: return open(path, r, encodinglatin-1)注意latin-1是最后兜底選項(xiàng)它能把每個(gè)字節(jié)都映射成一個(gè)字符保證文件不至于直接打不開但內(nèi)容顯示可能亂碼。這個(gè)兜底方案至少能讓你拿到原始字節(jié)數(shù)據(jù)便于進(jìn)一步分析而不是讓程序瞬間崩潰。5.2 路徑與權(quán)限問題為什么我的腳本別人跑不了100個(gè)腳本給團(tuán)隊(duì)其他人用時(shí)常常出現(xiàn)“我本地能跑他那邊就報(bào)錯(cuò)”。排除環(huán)境變量差異后90%的原因是腳本內(nèi)部用了絕對路徑或者用了當(dāng)前工作目錄假設(shè)。例如腳本里寫了report_dir ./reports但別人在別的目錄執(zhí)行路徑就指向了別處。規(guī)范做法是腳本默認(rèn)以“腳本文件所在目錄”為基準(zhǔn)而不是以“執(zhí)行命令時(shí)的當(dāng)前目錄”為基準(zhǔn)import pathlib BASE_DIR pathlib.Path(__file__).resolve().parent DEFAULT_REPORT_DIR BASE_DIR / reports另一個(gè)高頻坑是Shell腳本沒有執(zhí)行權(quán)限。每次寫完Shell腳本都要記得chmod x script.sh否則即使腳本邏輯完全正確別人用./script.sh運(yùn)行也會報(bào)Permission denied。如果打包給團(tuán)隊(duì)使用最好在文檔里寫清楚安裝命令。5.3 性能瓶頸數(shù)據(jù)量大時(shí)腳本卡死怎么處理日常需求的數(shù)據(jù)量通常不大但偶爾會遇到大數(shù)據(jù)集比如幾萬條Excel記錄、幾十GB的日志文件。這時(shí)候腳本設(shè)計(jì)上的差別就被放大了。我踩過最深的坑是在一個(gè)合并統(tǒng)計(jì)腳本里直接pd.read_excel讀取幾十個(gè)Excel文件每個(gè)文件幾萬行結(jié)果內(nèi)存占用沖到幾個(gè)GB腳本卡死。用pandas讀xlsx確實(shí)方便但Excel格式本身解壓解析開銷巨大。改成先批量轉(zhuǎn)CSV后再用流式處理速度和內(nèi)存占用都省了十倍以上。還有一個(gè)容易被忽視的性能殺手在循環(huán)體內(nèi)反復(fù)打開文件或者反復(fù)連接數(shù)據(jù)庫。這種問題很難從代碼靜態(tài)分析中看出來只能通過實(shí)際運(yùn)行時(shí)間和資源監(jiān)控定位。排查時(shí)用time python script.py先看總耗時(shí)再用top或pidstat看運(yùn)行期間的CPU和內(nèi)存曲線。如果CPU占用很低但耗時(shí)很長大概率在等待IO優(yōu)先優(yōu)化文件讀寫或網(wǎng)絡(luò)請求。5.4 使用頻率降低的信號什么時(shí)候應(yīng)該刪掉或重寫腳本維護(hù)腳本庫半年后我意識到“100個(gè)腳本”不能是一潭死水。如果一個(gè)腳本連續(xù)兩三個(gè)月都沒有被執(zhí)行過它就在消耗你的認(rèn)知資源。我的處理方式是移入archive/目錄標(biāo)記“已棄用”但保留歷史代碼。這樣既不打擾日常使用又保留了解決方案的參考價(jià)值。另一個(gè)信號是“改動越來越頻繁”。如果一個(gè)腳本每隔幾天就要改一次參數(shù)或邏輯說明你對它的需求理解還不夠準(zhǔn)確。與其一直打補(bǔ)丁不如停下來重寫。重寫時(shí)不要把舊代碼直接改兩行就算完事而是回到“它到底要解決什么核心問題”想一遍往往會發(fā)現(xiàn)可以簡化掉一半的復(fù)雜度。6. 從100到更多腳本庫的長期演進(jìn)6.1 沉淀模板而不是積累一次性代碼腳本數(shù)量過了一百之后真正有價(jià)值的不是代碼本身而是可復(fù)用的模式模板。我現(xiàn)在寫新腳本時(shí)會直接套用固定的腳本骨架頭部Docstring、參數(shù)解析、日志輸出、異常處理。這個(gè)骨架本身就是從100個(gè)腳本中總結(jié)出來的。#!/usr/bin/env python3 腳本用途說明 用法示例: python3 script_name.py --input xxx --output yyy 依賴: requests import argparse import logging import sys # 統(tǒng)一日志配置輸出到控制臺可指定日志文件 def setup_logging(log_fileNone): handlers [logging.StreamHandler()] if log_file: handlers.append(logging.FileHandler(log_file, encodingutf-8)) logging.basicConfig( levellogging.INFO, format%(asctime)s %(levelname)s %(message)s, handlershandlers ) def parse_args(): parser argparse.ArgumentParser(description) parser.add_argument(--input, requiredTrue) parser.add_argument(--output, default) parser.add_argument(--log, defaultNone, help日志文件路徑) return parser.parse_args() def main(): args parse_args() setup_logging(args.log) logging.info(f開始執(zhí)行參數(shù): {args}) # 核心邏輯 logging.info(執(zhí)行完成) if __name__ __main__: sys.exit(main())寫長得可能覺得模板本身沒什么技術(shù)含量但實(shí)際價(jià)值在于統(tǒng)一的參數(shù)風(fēng)格、統(tǒng)一的日志行為、統(tǒng)一的結(jié)構(gòu)。團(tuán)隊(duì)里任何人接手任何一個(gè)腳本都能立刻看懂入口和數(shù)據(jù)流向省去大量的解釋成本。6.2 文檔與檢索讓腳本庫“可搜索”腳本積累到一定規(guī)模檢索效率變得和編寫效率一樣重要。我維護(hù)了一個(gè)INDEX.md按分類記錄了每個(gè)腳本的名稱、一句話功能、使用頻率、是否推薦使用。這個(gè)文件本身也是腳本自動生成的每周運(yùn)行一次update_index.py掃描腳本頭部的Docstring和時(shí)間戳自動把內(nèi)容同步進(jìn)去。加上前文說的run_script.py統(tǒng)一入口完整的檢索鏈條是這樣的想找“用什么工具能批量壓縮圖片”grep -i 壓縮\|圖片\|image INDEX.md直接定位到腳本名。不記得準(zhǔn)確名字在統(tǒng)一入口執(zhí)行run_script.py --search 關(guān)鍵字自動遍歷所有腳本的Docstring和文件名。確認(rèn)后直接運(yùn)行參數(shù)風(fēng)格一致無需重新學(xué)習(xí)。這一步徹底改變了工具庫的使用體驗(yàn)。以前是“翻文件夾找半天”現(xiàn)在是“一條命令找到并執(zhí)行”日常使用頻率提升了兩倍都不止。6.3 安全執(zhí)行腳本庫變大后最容易忽略的事腳本庫變大后安全性是我后來才意識到的問題。批量腳本經(jīng)常涉及文件覆蓋、移動、刪除操作一旦邏輯寫錯(cuò)輕則數(shù)據(jù)錯(cuò)亂重則把重要文件清理掉。我給高危操作腳本加了兩道防線默認(rèn)--dry-run只打印操作計(jì)劃不實(shí)際執(zhí)行。強(qiáng)制要求顯式加--execute才能動手杜絕誤操作。執(zhí)行前自動備份受影響文件到.backup/目錄備份保留30天后再自動清理。這里有個(gè)小技巧刪除類操作不要直接用rm而是移到臨時(shí)trash目錄過幾天確認(rèn)沒問題再清空。用Python實(shí)現(xiàn)也很簡單shutil.move到~/.trash/即可。這套機(jī)制讓腳本在外人手里也足夠安全。7. 寫在最后的實(shí)踐心得100個(gè)腳本整理到這個(gè)程度我對“日常實(shí)用”四個(gè)字有了更具體的理解。所謂實(shí)用不是代碼多漂亮、技術(shù)多前沿而是你真正會去用、能放心用、出問題敢修。建議你按照這個(gè)思路把散落在自己電腦里的腳本都撈出來先分類、再規(guī)范命名、然后補(bǔ)上統(tǒng)一入口。整理這個(gè)動作本身的價(jià)值有時(shí)比寫新腳本還要大。最后分享一個(gè)我保留了很久的習(xí)慣每次解決完一個(gè)臨時(shí)性問題都順手把那個(gè)“一次性處理命令”沉淀成正式腳本。100個(gè)腳本就是這樣在日常工作中一點(diǎn)一點(diǎn)長出來的。工具庫不是規(guī)劃出來的而是積累出來的關(guān)鍵是你要有一套讓積累可持續(xù)的結(jié)構(gòu)。