skip to content

Python One-Liners

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

15 min read 60 snippets deep dive

Python One-Liners#

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

Hello, World#

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

Output:

Hello, World!

Current timestamp#

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

Output:

2026-04-25T14:32:07.843221

JSON pretty-print from stdin#

Pipe any JSON to Python for readable output:

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

Output:

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

Base64 encode / decode#

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

Output:

aGVsbG8gd29ybGQ=
hello world

URL encode / decode#

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:

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

Static file server#

Serve the current directory on port 8080:

python -m http.server 8080

Output:

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 -

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

Benchmark a snippet#

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

Output:

100000 loops, best of 5: 2.38 usec per loop

Count lines / words in stdin#

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:

23 lines, 62 words

Generate a random password#

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

Output:

Xt7mK3pN2qRsWvYu

Generate a UUID#

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

Output:

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

SHA-256 hash of a string#

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

Output:

2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

List pip packages as JSON#

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:

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#

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:

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

Quick CSV to JSON#

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:

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

Interactive Python REPL with imports pre-loaded#

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

Output:

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).

# -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:

65536

[!TIP] 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).

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:

{
  "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.

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

Output:

{
  "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.

# 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:

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

[!TIP] 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.

# 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.

# 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:

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.

# 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:

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.

# 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:

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.

# 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:

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.

# 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.

# 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'))
"

[!TIP] 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.

# 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.

# 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.

# 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):

  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.

# 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:

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#

[!WARNING] 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.

[!WARNING] 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')".

[!WARNING] 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.

[!WARNING] 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.

[!WARNING] 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.

[!WARNING] 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.

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.

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.

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.

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.

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"