python -c 一行流:系统管理速查 (One-Liner Cookbook)
章节概述
本章是一份实战速查手册:在 C 语言开发者的日常工作中,许多需要临时写 bash 命令或 C 小工具才能完成的任务,其实用 python -c "..." 一行就能搞定。本章按类别整理了文件操作、文本处理、JSON/CSV、网络请求、数学计算、系统信息等场景的常用一行流,每条都配有”替代了什么 bash/C 工作流”的说明。
核心理念:Python 是 C 开发者的”超级 Shell”。当你需要一个 awk/sed/grep 的 bash 管道串了 5 步才能完成的事情时,
python -c用 1 行就能做到——而且可读性更好、跨平台更一致、处理 Unicode/JSON/二进制数据时不会像 bash 那样容易出错。
第一节:文件与目录操作
当你在终端里批量处理文件时,bash 的 for f in *.c; do ... done 常常会遇到空格文件名、子目录递归、条件过滤等痛点。Python 的 os/glob/shutil/pathlib 一行流更健壮。
批量重命名:空格替换为下划线
# bash 的做法——遇到文件名含空格就会炸
for f in *; do mv "$f" "$(echo $f | tr ' ' '_')"; done
# python -c 一行——安全处理任意文件名
python -c "import os; [os.rename(f, f.replace(' ', '_')) for f in os.listdir('.')]"
os.listdir('.')列出当前目录所有条目,列表推导式遍历并执行os.rename。Python 字符串的replace方法天然支持 Unicode,不像tr只处理 ASCII。
查找当前目录下最大的 5 个文件
# bash —— 需要 du + sort + head 管道
du -sh * | sort -rh | head -5
# python -c
python -c "import os; files=[(os.path.getsize(f),f) for f in os.listdir('.') if os.path.isfile(f)]; [print(f'{s:>10} {n}') for s,n in sorted(files,reverse=True)[:5]]"递归统计每种文件扩展名的数量
# bash —— find + awk 组合
find . -type f | sed 's/.*\.//' | sort | uniq -c | sort -rn
# python -c:更清晰的输出,且 `collections.Counter` 不需 sort | uniq
python -c "import os,collections; c=collections.Counter(); [c.update([os.path.splitext(f)[1] or '(无后缀)']) for r,_,fs in os.walk('.') for f in fs]; [print(f'{v:>5} {k}') for k,v in c.most_common()]"
os.walk递归遍历目录树,collections.Counter一行完成统计+排序,比sort | uniq -c | sort -rn的管道更简洁。
批量修改文件权限
# 将所有 .sh 文件改为可执行
python -c "import os,glob; [os.chmod(f,0o755) for f in glob.glob('*.sh')]"
glob.glob支持通配符匹配,os.chmod的权限值用八进制0o755表示(对应 bash 的chmod 755)。
复制目录树(排除 .o 和 build/)
# bash —— rsync --exclude 需要记住复杂语法
rsync -av --exclude='*.o' --exclude='build/' src/ dst/
# python -c
python -c "import shutil; shutil.copytree('src','dst',ignore=shutil.ignore_patterns('*.o','build'))"第二节:文本处理——grep/sed/awk 的 Python 平替
C 开发者习惯用 grep 搜索日志、用 sed 替换文本、用 awk 提取列。但这些工具在跨平台(尤其是 Windows)、处理 Unicode、处理多行模式时各有局限。Python 一行流弥补这些短板。
grep 替代:搜索含特定模式的行
# bash grep —— 搜索所有 .c 文件中含 TODO 的行
grep -rn "TODO" --include="*.c" .
# python -c:等效一行
python -c "import os,re; [print(f'{r}/{f}:{i+1}:{l}',end='') for r,_,fs in os.walk('.') for f in fs if f.endswith('.c') for i,l in enumerate(open(r+'/'+f)) if 'TODO' in l]"sed 替代:全局替换
# 将当前目录所有 .txt 文件中的 "foo" 替换为 "bar"(原地修改)
python -c "
import fileinput, sys
for line in fileinput.input(sys.argv[1:], inplace=True):
print(line.replace('foo', 'bar'), end='')
" *.txt
fileinput模块的inplace=True直接原地修改文件(内部操作是先备份→重写→删除备份),等效于sed -i 's/foo/bar/g' *.txt,但在 Windows 上也同样工作。
awk 替代:提取第 N 列
# bash awk —— 提取 ps 输出的 PID 和 COMMAND 列
ps aux | awk '{print $2, $11}'
# python -c
ps aux | python -c "import sys; [print(*l.split()[1:2]+l.split()[10:11]) for l in sys.stdin]"统计代码行数(按文件类型)
# 统计项目中各类型文件的行数
python -c "
import os, collections
c = collections.Counter()
for r,_,fs in os.walk('.'):
for f in fs:
ext = os.path.splitext(f)[1] or '(none)'
try:
c[ext] += sum(1 for _ in open(r+'/'+f))
except: pass
for k,v in c.most_common():
print(f'{v:>8} lines {k}')
"这是
cloc或wc -l的轻量替代。选择c.most_common()按行数降序输出。
正则提取:从日志中提取所有 IP 地址并去重
# bash —— grep -oP 需要 GNU grep(macOS 默认不支持 -P)
grep -oP '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' access.log | sort -u
# python -c:跨平台,且可做更多处理
python -c "
import re, sys
ips = set(re.findall(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', sys.stdin.read()))
print('\n'.join(sorted(ips)))
" < access.log第三节:JSON 与 CSV 数据处理
C 语言处理 JSON 需要引入 cJSON/json-c/parson 等第三方库,处理 CSV 需要手动解析分隔符。Python 内置 json 和 csv 模块,一行读取并操作结构化数据。
从 API 获取 JSON 并提取字段
# 从 REST API 获取数据,提取 name 字段并排序输出
python -c "
import json, urllib.request
data = json.load(urllib.request.urlopen('https://api.github.com/repos/torvalds/linux/commits?per_page=10'))
for c in data:
print(c['commit']['author']['name'], c['commit']['message'].split('\n')[0][:60])
"一个
python -c代替了curl | jq | sort的管道。urllib.request是标准库,无需pip install requests。
CSV 转 JSON
# 将 data.csv 转换为 data.json
python -c "
import csv, json, sys
reader = csv.DictReader(open('data.csv'))
json.dump(list(reader), open('data.json','w'), indent=2, ensure_ascii=False)
"
csv.DictReader自动将第一行作为列名,每行转为字典。json.dump带indent=2美化输出。
JSON 转 CSV(提取指定列)
# 从 JSON 数组中提取 id 和 name 并写入 CSV
python -c "
import json, csv
data = json.load(open('users.json'))
writer = csv.DictWriter(open('out.csv','w'), fieldnames=['id','name'])
writer.writeheader()
[writer.writerow({'id':d['id'],'name':d['name']}) for d in data]
"命令行 JSON 格式化(jq 替代)
# bash jq —— 格式化压缩 JSON
cat minified.json | jq .
# python -c
python -c "import json,sys; print(json.dumps(json.load(sys.stdin),indent=2,ensure_ascii=False))" < minified.json
# 更短的版本——用 -m 标志
python -m json.tool minified.json
python -m json.tool是最短的方式。加--sort-keys可按键排序输出。
合并多个 CSV 文件
# 将 split_*.csv 合并为一个文件(保留表头一次)
python -c "
import csv, glob
writer = csv.writer(open('merged.csv','w'))
for i,f in enumerate(sorted(glob.glob('split_*.csv'))):
reader = csv.reader(open(f))
for j,row in enumerate(reader):
if j==0 and i>0: continue # 跳过后续文件的表头
writer.writerow(row)
"第四节:网络与系统信息
临时检测端口、发起 HTTP 请求、查看系统资源——这些操作在 C 中需要写几十行 socket 代码,在 Python 中用一行就能完成。
端口是否可连接
# 检测 localhost:8080 是否在监听
python -c "import socket; s=socket.socket(); s.settimeout(2); r=s.connect_ex(('127.0.0.1',8080)); print('OPEN' if r==0 else 'CLOSED'); s.close()"等效于
nc -zv 127.0.0.1 8080,但不依赖 netcat 是否安装。connect_ex返回 0 表示连接成功。
HTTP GET 快速测试
# 测试一个 URL 是否可达,输出状态码和响应体前 200 字符
python -c "
import urllib.request
try:
r = urllib.request.urlopen('http://httpbin.org/get', timeout=5)
print(f'Status: {r.status}')
print(r.read().decode()[:200])
except Exception as e:
print(f'Error: {e}')
"列出所有监听端口
# bash —— ss -tlnp 或 netstat -tlnp
ss -tlnp
# python -c 获取简易版本
python -c "
import subprocess, re
out = subprocess.check_output(['ss','-tlnp']).decode()
for line in out.split('\n'):
if 'LISTEN' in line:
print(line)
"当
ss/netstat可用时,直接用它们更简单。此处展示 Python 调用外部命令并解析输出的模式——这种”Python 作为胶水调用 C 编写的系统工具”正是本教程的核心思想。
获取 CPU/内存基本信息
# 读取 /proc/cpuinfo 获取 CPU 型号(Linux)
python -c "print([l.split(':')[1].strip() for l in open('/proc/cpuinfo') if 'model name' in l][0])"
# 读取 /proc/meminfo 获取内存总量(Linux)
python -c "
for l in open('/proc/meminfo'):
if l.startswith('MemTotal:'):
print(l.split()[1], l.split()[2])
break
"
/proc文件系统是 Linux 内核暴露的伪文件系统,由 C 语言编写的内核代码生成。Python 读取它就像读取普通文本文件,这正是”用 Python 操作 C 内核接口”的经典模式。
base64 编码/解码
# 编码字符串
echo -n "Hello World" | python -c "import sys,base64; print(base64.b64encode(sys.stdin.read().encode()).decode())"
# 解码
echo "SGVsbG8gV29ybGQ=" | python -c "import sys,base64; print(base64.b64decode(sys.stdin.read().strip()).decode())"第五节:数学计算与随机数
C 程序员需要 <math.h> + -lm 链接才能做数学计算,需要 srand()/rand() 才能生成随机数。Python 内置运算符和 math/random 模块零依赖可用。
快速计算
# 当作计算器用——Python 原生支持大整数和浮点
python -c "print(2 ** 100)" # 大整数
python -c "print(sum(range(1, 101)))" # 1+2+...+100
python -c "import math; print(math.factorial(20))" # 阶乘
python -c "print(hex(255), oct(255), bin(255))" # 进制转换C 语言计算
2**100需要unsigned long long溢出或引入 GMP 大数库。Python 整数自动扩展,无上限。
随机数生成
# 生成 10 个 1-100 的随机整数
python -c "import random; print([random.randint(1,100) for _ in range(10)])"
# 从列表中等概率随机选取
python -c "import random; print(random.choice(['gcc','clang','msvc']))"
# 生成随机密码(16 位字母数字)
python -c "import secrets,string; print(''.join(secrets.choice(string.ascii_letters+string.digits) for _ in range(16)))"
secrets模块使用操作系统级的加密安全随机源(Linux 上读取/dev/urandom),比random模块更适合生成密码、Token 等安全场景。
统计计算
# 从 stdin 读取一列数字,计算均值、最大、最小
echo -e "3\n7\n2\n9\n5" | python -c "
import sys
nums = [int(l) for l in sys.stdin]
print(f'count={len(nums)} sum={sum(nums)} avg={sum(nums)/len(nums):.2f} min={min(nums)} max={max(nums)}')
"一个
python -c替代了awk '{sum+=$1} END {print sum/NR}'这样的复杂 awk 脚本。
三角函数与常量
python -c "import math; print(f'π={math.pi:.15f} e={math.e:.15f}')"
python -c "import math; print(math.sin(math.radians(30)), math.cos(math.radians(60)))"第六节:一行流的组合技巧
真正的威力来自组合。以下展示如何将多个操作串联成一个 python -c 调用,同时保持可读性。
技巧 1:用 -c 内部换行
# 不要在 bash 单行中写超长代码——用引号内的换行
python -c "
import os, json, subprocess
# 步骤1:获取 C 源文件列表
files = [f for f in os.listdir('.') if f.endswith('.c')]
# 步骤2:统计每个文件的行数
stats = {f: sum(1 for _ in open(f)) for f in files}
# 步骤3:输出为 JSON
print(json.dumps(stats, indent=2))
"在
python -c "..."内部可以使用换行和缩进——Python 解析器只关心缩进一致性,不关心 bash 行的数量。
技巧 2:用 sys.argv 传参
# 而不是在 -c 字符串内部拼接变量
python -c "
import sys, os
pattern = sys.argv[1]
for f in os.listdir('.'):
if pattern in f:
print(f)
" "TODO"
sys.argv[1]接收外部参数,避免手动拼接字符串时引号灾难。
技巧 3:管道组合——Python 接在 bash 管道中间
# bash 生成数据 → Python 处理 → 输出结果
find . -name '*.c' | python -c "
import sys, os
for line in sys.stdin:
f = line.strip()
size = os.path.getsize(f)
print(f'{size:>10} {f}')
" | sort -rn | head -10Python 作为管道中一环:bash 负责文件发现,Python 负责数据转换,bash 继续排序。各取所长。
练习
以下题目用于验证本章所学内容:
| 题号 | 题目 | 链接 | 涉及知识点 |
|---|---|---|---|
| — | 本章无对应力扣题 | — | 请用动手练习题自检 |