Files
gh-basher83-lunar-claude-pl…/skills/python-uv-scripts/reference/bash-to-python.md
2025-11-29 18:00:18 +08:00

5.3 KiB

Converting Bash Scripts to Python uv Scripts

This document guides the conversion of bash scripts to Python uv scripts.

When Conversion Makes Sense

Good Candidates for Conversion

Convert when:

  • Script needs better error handling
  • Cross-platform compatibility required
  • Complex data processing needed
  • API interactions involved
  • Script will grow in complexity

Examples:

# Good candidate - API interaction
curl -X POST https://api.example.com/data \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"status": "active"}'

# Good candidate - Data processing
cat data.json | jq '.users[] | select(.active == true)'

# Good candidate - Complex logic
for file in $(find /data -name "*.log"); do
  count=$(grep -c "ERROR" "$file")
  if [ $count -gt 100 ]; then
    # Complex processing
  fi
done

Keep as Bash When

Don't convert when:

  • Simple file operations (cp, mv, mkdir)
  • Shell-specific features heavily used (job control, pipes)
  • System administration tasks
  • Script is <10 lines and works fine
  • Team primarily knows bash

Examples:

# Keep as bash - Simple operations
#!/bin/bash
mkdir -p /var/log/app
cp config.yaml /etc/app/

# Keep as bash - Shell-specific
#!/bin/bash
find /data -name "*.tmp" -mtime +7 -delete

# Keep as bash - System admin
#!/bin/bash
systemctl restart nginx
journalctl -u nginx -f

Common Conversions

File Operations

Bash:

#!/bin/bash
if [ -f "/etc/config.yaml" ]; then
  cp /etc/config.yaml /backup/
fi

Python:

#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///

from pathlib import Path
import shutil

config = Path("/etc/config.yaml")
if config.exists():
    shutil.copy(config, "/backup/")

Environment Variables

Bash:

#!/bin/bash
API_URL=${API_URL:-"https://api.example.com"}
if [ -z "$API_TOKEN" ]; then
  echo "Error: API_TOKEN not set" >&2
  exit 1
fi

Python:

#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///

import os
import sys

API_URL = os.getenv("API_URL", "https://api.example.com")
API_TOKEN = os.getenv("API_TOKEN")

if not API_TOKEN:
    print("Error: API_TOKEN not set", file=sys.stderr)
    sys.exit(1)

Running Commands

Bash:

#!/bin/bash
set -euo pipefail

output=$(systemctl status nginx)
if [ $? -ne 0 ]; then
  echo "Error: nginx not running"
  exit 1
fi

Python:

#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///

import subprocess
import sys

try:
    result = subprocess.run(
        ["systemctl", "status", "nginx"],
        capture_output=True,
        text=True,
        check=True
    )
    print(result.stdout)
except subprocess.CalledProcessError:
    print("Error: nginx not running", file=sys.stderr)
    sys.exit(1)

HTTP Requests

Bash:

#!/bin/bash
response=$(curl -s -X GET https://api.github.com/users/octocat)
name=$(echo "$response" | jq -r '.name')
echo "Name: $name"

Python:

#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "httpx>=0.27.0",
# ]
# ///

import httpx

response = httpx.get("https://api.github.com/users/octocat")
response.raise_for_status()
data = response.json()
print(f"Name: {data['name']}")

JSON Processing

Bash:

#!/bin/bash
jq '.users[] | select(.active == true) | .name' data.json

Python:

#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///

import json
from pathlib import Path

data = json.loads(Path("data.json").read_text())
active_names = [
    user["name"]
    for user in data["users"]
    if user.get("active")
]
print("\n".join(active_names))

Decision Framework

Should I convert this bash script?

├─ Is it >50 lines? → Consider conversion
├─ Does it process JSON/YAML? → Strong candidate
├─ Does it make API calls? → Strong candidate
├─ Does it have complex logic? → Consider conversion
├─ Does it need better error handling? → Consider conversion
├─ Is it mostly shell commands? → Keep as bash
└─ Is it <10 lines and works? → Keep as bash

Hybrid Approach

Sometimes the best solution is calling bash from Python:

#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///
"""
Hybrid: Use Python for logic, bash for system commands.
"""

import subprocess

def backup_with_rsync(source: str, dest: str):
    """Use rsync (better than reimplementing in Python)."""
    subprocess.run(
        ["rsync", "-av", "--delete", source, dest],
        check=True
    )

# Python logic here
# ...

# Leverage bash tools where appropriate
backup_with_rsync("/data/", "/backup/")

Summary

Convert to Python when:

  • Complex logic or data processing
  • API interactions
  • Cross-platform needs
  • Better error handling required
  • Will grow in complexity

Keep as Bash when:

  • Simple file operations
  • System administration
  • Heavily uses shell features
  • Works well and won't change
  • Team expertise is bash

Consider Hybrid:

  • Complex Python logic + system commands
  • Leverage both Python libraries and shell tools