Skip to main content

PyBash

GitHub Workflow Status (with branch) PyPI - Downloads PyPI GitHub

Write shell commands directly in Python. PyBash rewrites lines that start with $ or > into subprocess calls, so you get the brevity of a shell script with the rest of Python around it.

branch = ($git rev-parse --abbrev-ref HEAD).decode().strip()
$git fetch origin && git rebase origin/{{branch}} || echo "rebase failed"
count = $git log --oneline | wc -l
print(f"{branch}: {int(count)} commits")
  • $ commands never go through a shell. Arguments are split at transform time, and pipes, redirects and && / || / ; are run by PyBash itself, so a value can never turn into shell syntax.
  • > commands are handed to the shell as written, for globbing and expansion. Interpolated values are quoted for you.
  • One line in, one line out: tracebacks point at the line you wrote.
  • No dependencies. Python 3.11+.

Install

pip install pybash

Use

Run a script

pybash script.py [args...]      # or: python -m pybash script.py
pybash --show script.py         # print the generated Python instead of running it
pybash -c '$echo hello'

Modules the script imports from its own project may use the syntax too.

Transform source yourself

from pybash import transform

transform("$echo hello world")   # 'subprocess.run(["echo", "hello", "world"])'

Plain commands compile to bare subprocess calls. Commands with operators call a small helper in pybash.runtime; by default the generated code imports it in place, so the output only needs import subprocess. For tidier output, name the helper yourself and add the header:

import pybash

body = pybash.transform(source, runtime=pybash.RUNTIME_NAME)
code = pybash.header() + body                   # imports pybash.runtime
code = pybash.header(standalone=True) + body    # pastes the helper in: no pybash needed at run time

pybash.compile_source(source, filename) returns a code object ready for exec, and pybash.add_hook() installs an import hook for the current process.

Mistakes raise PybashSyntaxError, a SyntaxError whose filename, lineno, offset and text point at the original line.

Syntax

Run: $command

$python --version
$cp test.txt test_copy.txt

Returns the subprocess.CompletedProcess. A non-zero exit does not raise.

Capture: x = $command, ($command), $(command)

out = $cat test.txt
print(($cat test.txt).decode().strip())
lines = $(wc -l test.txt).decode().split()[0]

Captures are bytes, and raise subprocess.CalledProcessError on a non-zero exit. A capture not wrapped in brackets runs to the end of the line.

Operators

Operator Meaning
a | b pipe stdout of a into b
a |& b pipe stdout and stderr
a && b, a || b, a ; b run b if a succeeded / failed / either way
< file read stdin from a file
> file, >> file write / append stdout
2> file, 2>> file write / append stderr
&> file, &>> file write / append both
2>&1, >&2 send stderr to stdout / stdout to stderr
$sort < in.txt | uniq -c | sort -rn > counts.txt
$make build > build.log 2>&1 && echo ok || echo failed
newest = $ls -t | head -n 1

Operators work without surrounding spaces (a|b, 2>err.log). Quote or escape one to pass it as text: $echo 'a && b' \| c. Several output files on one command all receive the output ($echo hi > a.txt >> b.txt).

Background jobs (&), here-documents (<<) and other file descriptors are not supported in $ commands; use a > shell command for those.

Quoting

$ commands follow POSIX shell quoting: single quotes are literal, double quotes allow \" and \\, and a backslash escapes the next character. An unquoted # at the start of a word begins a comment. There is no globbing, ~ or $VAR expansion; use > when you need the shell.

A trailing backslash continues the command on the next line.

Interpolation

Form Meaning
{{ expr }} the value of any Python expression, converted with str()
f{ expr } the same, with f-string formatting available: f{n:03d}, f{name!r}
$git {{command}} {{get_option(command)}}
$kubectl get pods --show-{{display_type}}=true -n f{namespace}
$echo "{{user}} has f{count:,} files"

In a $ command an interpolated value is always exactly one argument, whatever it contains. Interpolation also applies inside quotes. To write the markers literally, escape them: \{{ and \f{.

Shell: >command

>ls .github/* | wc -l
>echo "hello {{name}}" > out.txt

The line is passed to the shell untouched. Interpolated values are quoted for where they appear (bare, inside "..." or inside '...'), so they are always data. To splice shell syntax in on purpose, use {{! expr }}:

pattern = "*.txt"
>ls {{! pattern }}

Upgrading from 0.3

  • Python 3.11+ is required; the ideas and token-utils dependencies are gone.
  • Arguments reach the command exactly as a shell would pass them. Previously backslashes were re-interpreted by Python ('a\\nb' became a newline) and a " inside an argument produced invalid code.
  • {{ x }} is converted with str(), may contain spaces and quotes, and no longer raises InvalidInterpolation for them.
  • Interpolated values in > commands are now quoted. Use {{! x }} for the old raw behavior.
  • > commands keep their quoting; previously quotes were stripped before the shell saw them.
  • a = $x | y now captures the pipeline's output instead of assigning a process object, and no cmd1 / fout variables leak into your code.
  • $a > f1 > f2 writes the output to both files; previously the second file received a copy of the first.
  • &&, ||, ;, 2>, &>, 2>&1, |& and $( ) are new. && used to raise NotImplementedError.
  • Generated lists are formatted ["ls", "-la"] and the result no longer ends with an added newline.
  • Text such as "total = $5" or "($x)" inside a Python string is no longer mistaken for a command.

Development

uv sync
make check     # format, lint (ruff + mypy), test
make demo

Metadata

Release files for PyBash 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for PyBash 0.4.0
File Size Uploaded
pybash-0.4.0.tar.gz 47.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for PyBash 0.4.0
File Interpreter ABI Platform
pybash-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 65.3 kB

Release files / pybash-0.4.0.tar.gz

Download URL pybash-0.4.0.tar.gz
Size 47.8 kB
Tags Source
SHA-256 checksum
How to use checksums
5c73e5ad1d07057dab29f8281108f9aada0a47708b71da0b8a37a9fa1398ccc3
BLAKE2b-256 checksum
How to use checksums
53dfe876fe2f96a1389d87596e0e1613a9dcadc9f542477818335a2c19f32b99
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / pybash-0.4.0-py3-none-any.whl

Download URL pybash-0.4.0-py3-none-any.whl
Size 17.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
03a4703d0562c0fc4683e3ef3dac87af52059990c7ab0ba17b45fdbd5cc120fa
BLAKE2b-256 checksum
How to use checksums
795575b84ea693567e4782b7f522368d90fd5261d9d2e3df84c24fba5b323ca8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page