---
name: bash-py
description: "Python 执行增强（uv heredoc 规范）。TRIGGER when: Bash 工具中需要执行 Python 代码（多行脚本、依赖安装、uv run 调用）。SKIP: 纯 shell 命令、不涉及 Python 的 Bash 操作。"
version: "1.0.0"
when_to_use: "当 Claude 准备在 Bash 工具中运行 Python 代码时，必须先加载此 skill 以遵守 uv heredoc 执行规范。触发场景：执行 Python 脚本、安装临时 Python 依赖、使用 uv 命令。BLOCKING: 在 Bash 中执行 Python 代码前必须先调用此 skill。"
user-invocable: true
argument-hint: "[--tips]"
effort: low
---

# Python 执行增强：uv heredoc 规范

你是在 Claude Code Bash 工具中通过 `uv run` 执行 Python 代码的专家。

**核心原则：少量多行代码，组合强力库，换取精准无噪音的精悍结果。**
最大化执行效率，最小化 token 消耗——一次 heredoc 调用完成目标，不啰嗦。

## Bash 工具中的 Python 执行约束

1. **禁止 `python` / `python3`** — 一律使用 `uv run`
2. **禁止 `pip install`** — 用 `uv run --with <pkg>` 按需加载
3. **禁止 `uv run -c "..."` 单行 hack** — 全部用 heredoc，保持可读性
4. **heredoc 定界符必须用单引号**（`<<'UV'`）— 防止 shell 变量展开

---

## 基础用法

```bash
uv run -q --with <pkg1> --with <pkg2> - <<'UV'
import subprocess, jc
data = jc.parse('dig', subprocess.check_output(['dig', 'example.com'], text=True), quiet=True)
print(data[0]['answer'])
UV
```

- `--with` 按需声明依赖，`uv` 自动解析安装，零配置
- `-q` 屏蔽 `Installed N packages` 提示
- `jc` 的 `quiet=True` 屏蔽平台 warning

---

## 强力库速查

以下库均通过 `--with` 加载，无需预先安装。可自由组合，几行代码替代复杂 shell 管道。

### CLI 输出 → 结构化数据

**`jc`** — 将 100+ 种 CLI 命令输出转为 Python dict/list，告别 awk/grep 文本解析。
支持：`dig`, `ps`, `ls`, `ifconfig`, `netstat`, `df`, `du`, `mount`, `uname`,
`ping`, `traceroute`, `whois`, `arp`, `route`, `systemctl`, `timedatectl`,
`xml`, `csv`, `ini`, `yaml`, `env` 等。

```bash
# dig → 结构化数据
uv run -q --with jc - <<'UV'
import subprocess, jc
data = jc.parse('dig', subprocess.check_output(['dig', 'example.com'], text=True), quiet=True)
for a in data[0]['answer']:
    print(f"{a['name']} {a['class']} {a['type']} {a['data']}")
UV

# ps → rich 表格（按内存排序 Top 10）
uv run -q --with jc --with rich - <<'UV'
import subprocess, jc
from rich.console import Console
from rich.table import Table
procs = jc.parse('ps', subprocess.check_output(['ps', 'aux'], text=True), quiet=True)
procs.sort(key=lambda p: float(p.get('mem_percent', 0)), reverse=True)
t = Table()
for c in ('user','pid','mem_percent','command'):
    t.add_column(c)
for p in procs[:10]:
    t.add_row(p['user'], str(p['pid']), f"{p['mem_percent']}%", p['command'][:60])
Console().print(t)
UV
```

### JSON / 数据查询

| 库 | 擅长 |
| --- | --- |
| `jmespath` | JSON 查询语言，一行提取嵌套字段 |
| `jsonpath-ng` | JSONPath 查询，支持过滤表达式 |
| `pydantic` | 数据校验 + 序列化 + JSON Schema 生成 |
| `polars` | 高性能 DataFrame，比 pandas 快 |

```bash
# JMESPath 提取 GitHub 仓库信息
uv run -q --with httpx --with jmespath - <<'UV'
import httpx, jmespath
data = httpx.get("https://api.github.com/users/astral-sh/repos?per_page=30").json()
names = jmespath.search("[*].[name,stargazers_count,language]", data)
for n in names:
    print(f"{n[0]:30} {n[1]:>6} {n[2] or '-'}")
UV
```

### HTML / XML 解析

| 库 | 擅长 |
| --- | --- |
| `beautifulsoup4` | HTML 容错解析 |
| `lxml` | 高性能 XML/HTML，XPath 支持 |
| `feedparser` | RSS/Atom 解析 |

```bash
# 抓取页面所有链接
uv run -q --with httpx --with beautifulsoup4 - <<'UV'
from bs4 import BeautifulSoup
import httpx
soup = BeautifulSoup(httpx.get("https://example.com").text, "html.parser")
for a in soup.find_all("a", href=True):
    print(f"{a.get_text(strip=True):40} → {a['href']}")
UV
```

### 文件格式转换

| 库 | 格式 |
| --- | --- |
| `openpyxl` | Excel (.xlsx) 读写 |
| `python-docx` | Word (.docx) 读写 |
| `pypdf` | PDF 读取/合并/拆分 |
| `pyyaml` | YAML 读写 |
| `toml` | TOML 读写 |
| `pillow` | 图像处理（裁剪、缩放、格式转换） |

```bash
# Excel → CSV
uv run -q --with openpyxl - <<'UV'
from openpyxl import load_workbook
import csv, sys
ws = load_workbook("data.xlsx").active
csv.writer(sys.stdout).writerows(ws.iter_rows(values_only=True))
UV

# PDF 提取文本
uv run -q --with pypdf - <<'UV'
from pypdf import PdfReader
for page in PdfReader("doc.pdf").pages:
    print(page.extract_text())
UV
```

### 网络请求

| 库 | 擅长 |
| --- | --- |
| `httpx` | 现代 HTTP 客户端，同步/异步，HTTP/2 |
| `requests` | 经典 HTTP，API 最简洁 |
| `websocket-client` | WebSocket 客户端 |

```bash
# 下载文件并显示进度
uv run -q --with httpx --with rich - <<'UV'
import httpx
from rich.progress import Progress
url = "https://example.com/large-file.zip"
with httpx.stream("GET", url, follow_redirects=True) as r:
    total = int(r.headers.get("content-length", 0))
    with Progress() as p, open("file.zip", "wb") as f:
        t = p.add_task("Downloading", total=total)
        for chunk in r.iter_bytes():
            f.write(chunk)
            p.update(t, advance=len(chunk))
print("done")
UV
```

### 文本 / 编码

| 库 | 擅长 |
| --- | --- |
| `ftfy` | 修复乱码文本（mojibake） |
| `chardet` | 编码检测 |
| `python-dateutil` | 灵活日期解析（比 strptime 强） |
| `regex` | 增强 re（模糊匹配、Unicode 属性） |
| `python-slugify` | 生成 URL-safe slug |

### 终端输出

| 库 | 擅长 |
| --- | --- |
| `rich` | 表格、进度条、语法高亮、Markdown 渲染 |
| `tqdm` | 一行进度条 |

```bash
# rich 表格渲染
uv run -q --with httpx --with rich - <<'UV'
from rich.console import Console
from rich.table import Table
import httpx
repos = httpx.get("https://api.github.com/users/astral-sh/repos?per_page=10").json()
t = Table(title="Astral Repos")
t.add_column("Name"); t.add_column("Stars", justify="right"); t.add_column("Lang")
for r in sorted(repos, key=lambda x: x['stargazers_count'], reverse=True):
    t.add_row(r['name'], str(r['stargazers_count']), r.get('language') or '-')
Console().print(t)
UV
```

---

## heredoc 规则

1. **单引号定界符** — `<<'UV'` 而非 `<<UV`
2. **结束定界符独占一行** — 前后不能有空格或缩进

## `--tips` 参数

当用户传入 `--tips` 时，仅输出以下速查表：

```
uv run -q --with <pkg> - <<'UV' ... UV
```
