cheat sheet

Python One-Liners

Useful Python one-liners runnable directly from the shell with python -c or python -m. No file creation needed.

Python One-Liners

All examples run from your terminal — no Python file needed. Assumes python points to Python 3.

Hello, World

bash
python -c "print('Hello, World!')"

Output:

text
Hello, World!

Current timestamp

bash
python -c "from datetime import datetime; print(datetime.now().isoformat())"

Output:

text
2026-04-25T14:32:07.843221

JSON pretty-print from stdin

Pipe any JSON to Python for readable output:

bash
echo '{"name":"Alice","age":30,"active":true}' \
  | python -c "import sys,json; print(json.dumps(json.load(sys.stdin), indent=2))"

Output:

text
{
  "name": "Alice",
  "age": 30,
  "active": true
}

Base64 encode / decode

bash
python -c "import base64; print(base64.b64encode(b'hello world').decode())"
python -c "import base64; print(base64.b64decode('aGVsbG8gd29ybGQ=').decode())"

Output:

text
aGVsbG8gd29ybGQ=
hello world

URL encode / decode

bash
python -c "from urllib.parse import quote; print(quote('hello world & more'))"
python -c "from urllib.parse import unquote; print(unquote('hello%20world%20%26%20more'))"

Output:

text
hello%20world%20%26%20more
hello world & more

Static file server

Serve the current directory on port 8080:

bash
python -m http.server 8080

Output:

text
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...
127.0.0.1 - - [25/Apr/2026 14:00:00] "GET / HTTP/1.1" 200 -

Add --directory /path/to/dir to serve a specific directory instead of the current one.

Benchmark a snippet

bash
python -m timeit -n 100000 "sum(range(100))"

Output:

text
100000 loops, best of 5: 2.38 usec per loop

Count lines / words in stdin

bash
cat /etc/hosts | python -c "import sys; lines=sys.stdin.readlines(); print(f'{len(lines)} lines, {sum(len(l.split()) for l in lines)} words')"

Output:

text
23 lines, 62 words

Generate a random password

bash
python -c "import secrets, string; print(secrets.token_urlsafe(16))"

Output:

text
Xt7mK3pN2qRsWvYu

Generate a UUID

bash
python -c "import uuid; print(uuid.uuid4())"

Output:

text
3f7c4b2e-1a8d-4e9f-b0c3-72d5e1f6a309

SHA-256 hash of a string

bash
python -c "import hashlib; print(hashlib.sha256(b'hello').hexdigest())"

Output:

text
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

List pip packages as JSON

bash
pip list --format=json | python -c "import sys,json; pkgs=json.load(sys.stdin); [print(p['name'],p['version']) for p in pkgs[:5]]"

Output:

text
certifi 2024.2.2
charset-normalizer 3.3.2
click 8.1.7
fastapi 0.111.1
httpx 0.27.0

Flatten a nested list

bash
python -c "
nested = [[1,2],[3,[4,5]],6]
flat = list(__import__('itertools').chain.from_iterable(x if isinstance(x,list) else [x] for x in nested))
print(flat)
"

Output:

text
[1, 2, 3, [4, 5], 6]

Quick CSV to JSON

bash
python -c "
import csv, json, sys
reader = csv.DictReader(sys.stdin)
print(json.dumps(list(reader), indent=2))
" << 'EOF'
name,age,city
Alice,30,NYC
Bob,25,LA
EOF

Output:

text
[
  {
    "name": "Alice",
    "age": "30",
    "city": "NYC"
  },
  {
    "name": "Bob",
    "age": "25",
    "city": "LA"
  }
]

Interactive Python REPL with imports pre-loaded

bash
python -i -c "import json, os, sys, pathlib; from pathlib import Path; print('Ready. Path, json, os, sys loaded.')"

Output:

text
Ready. Path, json, os, sys loaded.
>>>

How python -c and python -m differ

The -c flag runs the argument string as a tiny module; the -m flag runs an installed module as __main__. Both let you skip writing a .py file, but they hit different parts of the toolchain. Reach for -c for ad-hoc Python expressions; reach for -m for tools that already ship as modules (http.server, json.tool, timeit, pip, venv, unittest).

bash
# -c: run an inline statement
python -c "print(2 ** 16)"

# -m: run a module
python -m json.tool < data.json
python -m http.server 8080
python -m timeit "sum(range(100))"
python -m venv .venv
python -m unittest test_module

Output:

text
65536

Multi-line -c works fine when you use real newlines inside double quotes: python -c "import sys$'\n'for line in sys.stdin: print(line.upper(), end='')" — but for anything past three lines, a heredoc (python - <<'PY' ... PY) is more readable than escaping inline.

Multi-line one-liners with heredocs

Most "one-liners" of any complexity are really short scripts run from a heredoc. The trick is the lonely - (read script from stdin) plus a quoted heredoc tag (<<'PY' — the quotes prevent shell expansion).

bash
python - <<'PY'
import sys, json
data = {"now": __import__("datetime").datetime.utcnow().isoformat(),
        "argv": sys.argv,
        "pid": __import__("os").getpid()}
print(json.dumps(data, indent=2, default=str))
PY

Output:

text
{
  "now": "2026-05-25T11:43:09.842321",
  "argv": ["-"],
  "pid": 48211
}

Pretty-print Python data with json.tool

json.tool is a stdlib pretty-printer accessible from the shell — python -m json.tool reads JSON from stdin (or a file) and writes formatted output. Use --sort-keys for stable diffs and --indent N to control width.

bash
echo '{"b":1,"a":[3,2,1]}' | python -m json.tool --sort-keys --indent 2

Output:

text
{
  "a": [
    3,
    2,
    1
  ],
  "b": 1
}

Filter a JSON document like jq

jq is the canonical tool, but if you don't have it, python -c plus json.load(sys.stdin) is a one-line fallback that runs anywhere Python does. Extract a nested key, filter records, or reshape a payload without leaving the shell.

bash
# Extract a nested field
echo '{"user":{"name":"Alice","age":30}}' \
  | python -c "import json,sys; print(json.load(sys.stdin)['user']['name'])"

# Filter a list by predicate
echo '[{"name":"Alice","age":30},{"name":"Bob","age":17}]' \
  | python -c "import json,sys; [print(u['name']) for u in json.load(sys.stdin) if u['age']>=18]"

# Reshape — flatten to lines of key=value
echo '{"host":"myhost","port":8080,"tls":true}' \
  | python -c "import json,sys; [print(f'{k}={v}') for k,v in json.load(sys.stdin).items()]"

# Pretty-print only specific keys
echo '{"a":1,"b":2,"c":3}' \
  | python -c "import json,sys; d=json.load(sys.stdin); print(json.dumps({k:d[k] for k in ('a','c')}, indent=2))"

Output:

text
Alice
Alice
host=myhost
port=8080
tls=True
{
  "a": 1,
  "c": 3
}

For full jq-equivalent power inside Python, install jq's Python binding (pip install jq) or glom (pip install glom) — both give you path expressions over nested dicts. For one-shot CLI use though, plain stdlib is enough.

YAML / TOML / CSV one-liners

For YAML and TOML you need a library (PyYAML or stdlib tomllib on 3.11+). CSV ships with the standard library.

bash
# YAML → JSON
pip install pyyaml -q
cat config.yaml | python -c "import yaml,sys,json; print(json.dumps(yaml.safe_load(sys.stdin), indent=2))"

# TOML (Python 3.11+) → JSON
cat pyproject.toml | python -c "import tomllib,sys,json; print(json.dumps(tomllib.loads(sys.stdin.read()), indent=2))"

# CSV column extraction — print column 2 of a CSV
cat data.csv | python -c "import csv,sys; [print(r[1]) for r in csv.reader(sys.stdin) if r]"

# CSV → TSV
cat data.csv | python -c "import csv,sys; w=csv.writer(sys.stdout, delimiter='\t'); [w.writerow(r) for r in csv.reader(sys.stdin)]"

# CSV column average
cat data.csv | python -c "
import csv, statistics, sys
rows = list(csv.DictReader(sys.stdin))
print(statistics.mean(float(r['age']) for r in rows))
"

Pythonic regex from the shell

Drop into Python when grep -P is missing (macOS BSD grep) or when the substitution involves groups or look-arounds that POSIX sed can't express.

bash
# Print lines matching pattern
cat /etc/hosts | python -c "import re,sys; [print(l, end='') for l in sys.stdin if re.search(r'^127', l)]"

# Extract all capture groups
echo "alice 30, bob 25" | python -c "
import re, sys
for m in re.finditer(r'(\w+)\s+(\d+)', sys.stdin.read()):
    print(m.group(1), '=', m.group(2))
"

# Substitute with named groups
echo "alice@example.com" | python -c "
import re, sys
print(re.sub(r'(?P<u>\w+)@(?P<d>[\w.]+)', r'\g<u> AT \g<d>', sys.stdin.read()), end='')
"

Output:

text
127.0.0.1   localhost
127.0.1.1   myhost
alice = 30
bob = 25
alice AT example.com

Calculator and math

The Python REPL is the world's most-installed scientific calculator. For one-off math, -c is the fastest path.

bash
# Plain arithmetic
python -c "print(2 ** 64)"
python -c "print(3.14159 * 5 ** 2)"

# Trig and logs
python -c "import math; print(math.degrees(math.atan2(1, 1)))"
python -c "import math; print(math.log2(1_000_000))"

# Floor division and remainder
python -c "print(divmod(100, 7))"

# Hex / oct / bin / int with base
python -c "print(hex(255), oct(8), bin(13))"
python -c "print(int('1010', 2), int('ff', 16))"

# Fractions and decimals (exact arithmetic)
python -c "from fractions import Fraction; print(Fraction(1,3) + Fraction(1,6))"
python -c "from decimal import Decimal; print(Decimal('0.1') + Decimal('0.2'))"

Output:

text
18446744073709551616
78.53975
45.0
19.931568569324174
(14, 2)
0xff 0o10 0b1101
10 255
1/2
0.3

Date and time

datetime, time, and zoneinfo (3.9+) cover almost every date one-liner you'll need. For ISO formatting use .isoformat(); for human-readable, use strftime.

bash
# Now in different forms
python -c "from datetime import datetime; print(datetime.now().isoformat())"
python -c "from datetime import datetime; print(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC'))"

# Today in a specific timezone (Python 3.9+ stdlib)
python -c "from datetime import datetime; from zoneinfo import ZoneInfo; print(datetime.now(ZoneInfo('Asia/Kolkata')).isoformat())"

# Parse a date and add days
python -c "from datetime import date, timedelta; print(date.fromisoformat('2026-01-01') + timedelta(days=120))"

# Days between two dates
python -c "from datetime import date; print((date(2026,12,31) - date.today()).days, 'days left')"

# Unix epoch seconds
python -c "import time; print(int(time.time()))"
python -c "from datetime import datetime; print(datetime.fromtimestamp(1700000000).isoformat())"

Output:

text
2026-05-25T11:43:09.842321
2026-05-25 06:13:09 UTC
2026-05-25T11:43:09.842321+05:30
2026-05-01
220 days left
1748167389
2023-11-14T19:43:20

Hashing — md5, sha1, sha256, blake2b

hashlib covers every common digest. To hash a file, read it in chunks to avoid loading huge files into memory.

bash
# Hash a literal string
python -c "import hashlib; print(hashlib.md5(b'hello').hexdigest())"
python -c "import hashlib; print(hashlib.sha1(b'hello').hexdigest())"
python -c "import hashlib; print(hashlib.sha256(b'hello').hexdigest())"
python -c "import hashlib; print(hashlib.blake2b(b'hello', digest_size=16).hexdigest())"

# Hash a file (streaming)
python -c "
import hashlib, sys
h = hashlib.sha256()
with open(sys.argv[1], 'rb') as f:
    for chunk in iter(lambda: f.read(8192), b''):
        h.update(chunk)
print(h.hexdigest())
" /etc/hosts

# HMAC
python -c "import hmac, hashlib; print(hmac.new(b'secret', b'message', hashlib.sha256).hexdigest())"

Output:

text
5d41402abc4b2a76b9719d911017c592
aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
324dcf027dd4a30a932c441f365a25e8

File and directory one-liners

Pair python -c with pathlib for portable filesystem snippets that work on Windows, macOS, and Linux.

bash
# Print absolute path of relative input
python -c "from pathlib import Path; import sys; print(Path(sys.argv[1]).resolve())" notes.txt

# List Python files under cwd, recursively
python -c "from pathlib import Path; [print(p) for p in sorted(Path('.').rglob('*.py'))]"

# Sum the size of all files in a directory
python -c "from pathlib import Path; print(sum(f.stat().st_size for f in Path('.').rglob('*') if f.is_file()), 'bytes')"

# Find the 5 largest files under cwd
python -c "
import heapq
from pathlib import Path
top = heapq.nlargest(5,
    ((p.stat().st_size, p) for p in Path('.').rglob('*') if p.is_file()),
    key=lambda x: x[0])
for size, p in top: print(f'{size:>10}  {p}')
"

# Touch a file (create or update mtime)
python -c "from pathlib import Path; Path('marker').touch()"

# Remove empty directories under cwd
python -c "
from pathlib import Path
for d in sorted(Path('.').rglob('*'), key=lambda p: -len(p.parts)):
    if d.is_dir():
        try: d.rmdir()
        except OSError: pass
"

HTTP requests with the standard library

Even without requests, the stdlib (urllib.request, http.client) can fetch URLs in one line.

bash
# GET a URL and print
python -c "import urllib.request; print(urllib.request.urlopen('https://httpbin.org/ip').read().decode())"

# Download a file (binary safe)
python -c "
import urllib.request, sys
urllib.request.urlretrieve(sys.argv[1], sys.argv[2])
" https://example.com/file.zip /tmp/file.zip

# POST JSON
python -c "
import json, urllib.request
body = json.dumps({'q': 'hello'}).encode()
req = urllib.request.Request('https://httpbin.org/post', data=body,
                              headers={'Content-Type': 'application/json'})
print(urllib.request.urlopen(req).read().decode())
"

# Send a header (User-Agent) and print response status
python -c "
import urllib.request
r = urllib.request.urlopen(urllib.request.Request('https://example.com',
                                                    headers={'User-Agent': 'mycli/1.0'}))
print(r.status, r.headers.get('Content-Type'))
"

The stdlib is fine for one-offs but lacks retries, connection pooling, and TLS verification toggles. For real applications, install httpx or requests.

Compression and archives

zipfile, tarfile, gzip, and bz2 cover archive creation, listing, and extraction from the shell.

bash
# Create a ZIP from a directory
python -c "
import shutil, sys
shutil.make_archive(sys.argv[1], 'zip', sys.argv[2])
" backup ./src

# Extract a ZIP
python -c "import zipfile,sys; zipfile.ZipFile(sys.argv[1]).extractall(sys.argv[2])" archive.zip /tmp

# List ZIP contents
python -c "import zipfile,sys; [print(n) for n in zipfile.ZipFile(sys.argv[1]).namelist()]" archive.zip

# Gzip a single file
python -c "
import gzip, shutil, sys
with open(sys.argv[1], 'rb') as r, gzip.open(sys.argv[1] + '.gz', 'wb') as w:
    shutil.copyfileobj(r, w)
" data.csv

# Tarball a folder
python -c "
import tarfile, sys
with tarfile.open(sys.argv[1] + '.tar.gz', 'w:gz') as t:
    t.add(sys.argv[1])
" project

Encoding tricks

Beyond base64, the stdlib speaks hex, ROT13, quoted-printable, and many text encodings via codecs.

bash
# Hex
python -c "print(b'hello'.hex())"
python -c "print(bytes.fromhex('68656c6c6f').decode())"

# ROT-13
python -c "import codecs; print(codecs.encode('Hello World', 'rot_13'))"

# Quoted-printable
python -c "import quopri; print(quopri.encodestring(b'naïve text').decode())"

# Detect encoding (best-effort)
python -c "
import chardet, sys
data = sys.stdin.buffer.read()
print(chardet.detect(data))
" < some_file

Counting, sorting, deduplicating — replace awk/sort/uniq

collections.Counter makes the common "count occurrences" pipeline a one-liner. For sort-by-value, sorted(..., reverse=True) over .most_common() is canonical.

bash
# Word frequency in a file
cat /etc/hosts | python -c "
import sys, collections, re
words = re.findall(r'\w+', sys.stdin.read().lower())
for w, n in collections.Counter(words).most_common(10):
    print(f'{n:>4}  {w}')
"

# Deduplicate preserving order (set + filter)
printf "a\nb\na\nc\nb\n" | python -c "
import sys
seen = set()
for line in sys.stdin:
    if line not in seen:
        seen.add(line); sys.stdout.write(line)
"

# Sort numerically (real numeric, not lexicographic)
printf "10\n2\n30\n4\n" | python -c "import sys; [print(n) for n in sorted(int(l) for l in sys.stdin)]"

# Histogram
printf "a\nb\na\nc\nb\nb\n" | python -c "
import sys, collections
c = collections.Counter(l.strip() for l in sys.stdin)
m = max(c.values())
for k, v in c.most_common():
    print(f'{k:>3} {\"█\"*v:<{m}} {v}')
"

Output (histogram example):

text
  b ███ 3
  a ██  2
  c █   1

Permutations, combinations, products — itertools from the shell

Combinatorics one-liners are the cleanest demonstration of itertools. They're also surprisingly useful in scripting — generating test inputs, brute-force search spaces, or coverage matrices.

bash
# All 2-letter permutations of ABC
python -c "from itertools import permutations; [print(''.join(p)) for p in permutations('ABC', 2)]"

# All 3-bit combinations
python -c "from itertools import product; [print(''.join(p)) for p in product('01', repeat=3)]"

# Cartesian product (each env × each region)
python -c "
from itertools import product
for env, region in product(['dev','staging','prod'], ['us-east','eu-west','ap-south']):
    print(f'{env}/{region}')
"

# Pairwise (sliding window of 2) — 3.10+
python -c "from itertools import pairwise; [print(a, b) for a, b in pairwise([1,2,3,4,5])]"

# Group consecutive equal items
python -c "
from itertools import groupby
data = 'aaabbcaaaa'
for key, grp in groupby(data):
    print(key, len(list(grp)))
"

Output:

text
AB
AC
BA
BC
CA
CB
a 3
b 2
c 1
a 4

See itertools & functools for the full set of combinator helpers — chain, accumulate, batched, compress, starmap, and the rest are all callable from a -c one-liner.

Comparison with awk, sed, jq, and xargs

Python one-liners compete directly with classic Unix tools — each has a sweet spot. The right tool depends on the input shape, the transformation, and how much portability you need.

TaskBest toolPython one-liner suffices when
Column extractionawk (awk '{print $2}')Columns are CSV/TSV and need real parsing
Stream substitutionsedSubstitution involves named groups or unicode
JSON path / filterjqjq isn't installed; payload fits in memory
Per-line transformawk / sedLogic exceeds 50 chars; need real types
Sort numericallysort -nYou also need to compute or filter at the same time
Counting / histogramsort | uniq -cYou want sorted output by frequency, not name
Pipe-fan parallel execxargs -P / parallelYou want type-checked arguments + retries
Time / date arithmeticdate -d (GNU)Crossplatform: date -d syntax differs on BSD/macOS
Hashingsha256sumYou need to combine hashing with parsing
Base64base64You need to chain with json/urlencoding/regex

Rule of thumb: if the Unix tool exists and ships everywhere you care about, use it — it's faster and shorter. Reach for python -c when you need real types (dates, JSON, regex with named groups), portable behaviour across macOS and Linux, or composition that would take multiple piped Unix tools.

Common pitfalls

Quoting on Windows is different. cmd.exe strips double quotes from python -c "..." arguments in surprising ways. PowerShell handles it more cleanly. Prefer python -c '...' (single quotes) on macOS/Linux/PowerShell and reserve double quotes when you need shell variable interpolation.

print adds a newline. Pipe python -c "print('x')" into wc -c and you get 2, not 1. Pass end="" or write to sys.stdout directly: python -c "import sys; sys.stdout.write('x')".

exec(open(f).read()) is not the same as running a file. It runs in the current namespace, has weird __file__ semantics, and won't catch syntax errors with a useful traceback. Prefer python myfile.py or runpy.run_path(...) for proper script invocation.

List comprehensions for side effects look "Pythonic" but aren't. [print(x) for x in seq] builds a throwaway list of Nones. It works, but a for loop is clearer and avoids the false impression that you're collecting results. Use it sparingly in one-liners where brevity wins.

python -c runs in __main__, not a fresh interpreter setup. That means no if __name__ == "__main__" guard, no __file__, and sys.argv[0] is -c. Tools that depend on these (some logging configs, multiprocessing) misbehave.

open() without encoding= is locale-dependent. On Windows it might default to cp1252; on Linux to UTF-8. Always pass encoding="utf-8" explicitly in cross-platform one-liners.

Real-world recipes

Find broken JSON files in a directory

Iterate every .json under cwd, try to parse each, and print only the ones that fail. Useful before re-running a batch ingest.

bash
python - <<'PY'
import json
from pathlib import Path
for p in sorted(Path(".").rglob("*.json")):
    try:
        json.loads(p.read_text(encoding="utf-8"))
    except Exception as e:
        print(f"BROKEN {p}: {e}")
PY

Convert a directory of CSVs into one combined JSON

A common ETL one-liner — concatenate every .csv in data/ into a single JSON array, tagging each row with its source filename.

bash
python - <<'PY'
import csv, json
from pathlib import Path
out = []
for p in sorted(Path("data").rglob("*.csv")):
    with p.open(encoding="utf-8") as f:
        for row in csv.DictReader(f):
            row["__source__"] = p.name
            out.append(row)
print(json.dumps(out, indent=2))
PY

Tiny HTTP API mock with http.server

http.server ships with the stdlib. Combine with a BaseHTTPRequestHandler subclass in a heredoc and you have a single-file mock API in under 20 lines — no Flask required.

bash
python - <<'PY'
import json
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.end_headers()
        self.wfile.write(json.dumps({"ok": True, "path": self.path}).encode())

print("listening on :8765")
ThreadingHTTPServer(("0.0.0.0", 8765), Handler).serve_forever()
PY

Rename a batch of files with a regex pattern

A safer replacement for rename (which varies wildly across distros). Always run the dry-run first.

bash
python - <<'PY'
import re
from pathlib import Path
DRY = True
pattern = re.compile(r"^IMG_(\d{4})\.JPG$", re.IGNORECASE)
for p in sorted(Path(".").iterdir()):
    m = pattern.match(p.name)
    if not m: continue
    target = p.with_name(f"photo_{m.group(1)}.jpg")
    print(f"{'DRY ' if DRY else 'MV  '}{p}  ->  {target}")
    if not DRY:
        p.rename(target)
PY

Read a .env file into the current shell

A Python alternative to set -a; source .env; set +a that handles quoting and comments correctly.

bash
eval "$(python - <<'PY' .env
import sys, shlex
for raw in open(sys.argv[1]):
    line = raw.strip()
    if not line or line.startswith("#"): continue
    if "=" not in line: continue
    k, v = line.split("=", 1)
    print(f"export {k.strip()}={shlex.quote(v.strip())}")
PY
)"
echo "$DATABASE_URL"