Python-first interactive shell for Debian and Unix-like systems
Project description
PySH
Python-first interactive shell for Debian and Unix-like systems.
PySH is a small, dependency-free interactive shell written in pure Python.
It is packaged as a regular PyPI distribution (pysh-shell), installs a
single console command (pysh), and is designed to feel familiar to anyone
used to a Bourne-style shell while remaining hackable from Python.
The 0.1.1 release targets Python 3.13+ and is validated on Debian 13.
Features
- Interactive REPL with command history (
~/.pysh_history). - Welcome banner, configurable prompt with user and CWD (
~collapsed). - Robust quote-aware parser:
- Splits chains on
;,&&,||only outside of quotes. - Splits pipelines on
|only outside of quotes.
- Splits chains on
- Pipelines with correctly managed file-descriptor handover.
- Redirection:
<,>,>>,2>,2>>,&>,&>>. - Local variables (
NAME=value) and exported environment variables (export NAME=value) with$NAME/${NAME}expansion. - Aliases with sane defaults and user overrides via
alias. - Startup file
~/.pyshrc(and thesourcebuiltin) for persistent customisation. - Basic tab completion for aliases, builtins, files and directories.
- Clean Ctrl+C (cancels current line, keeps the shell alive) and Ctrl+D (exits the shell).
Installation
From PyPI
pip install pysh-shell
Then start the shell with:
pysh
Development install
python3.13 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
Running
pysh # console entry point installed by the wheel
python -m pysh # equivalent module entry point
Builtins
Implemented directly inside the shell (no subprocess spawned):
| Builtin | Description |
|---|---|
cd |
Change the current working directory. |
pwd |
Print the current working directory. |
alias |
Define or display aliases. |
export |
Define or display exported environment vars. |
source |
Execute commands from a file (also .). |
exit |
Exit the shell with an optional status code. |
quit |
Same as exit. |
Operators
| Operator | Meaning |
|---|---|
cmd1 ; cmd2 |
Run cmd1, then unconditionally run cmd2. |
cmd1 && cmd2 |
Run cmd2 only if cmd1 exits with status 0. |
cmd1 || cmd2 |
Run cmd2 only if cmd1 exits with non-zero status. |
cmd1 | cmd2 |
Pipe cmd1's stdout into cmd2's stdin. |
Operators inside single or double quotes are treated as literal text.
echo "🐍 PySH v1.0 | Python 3.13.5"
python3.13 -c "import subprocess; print('ok')"
Redirection
| Syntax | Effect |
|---|---|
< file |
Read stdin from file. |
> file |
Write stdout to file (truncate). |
>> file |
Write stdout to file (append). |
2> file |
Write stderr to file (truncate). |
2>> file |
Write stderr to file (append). |
&> file |
Write stdout + stderr to file. |
&>> file |
Append stdout + stderr to file. |
ls -la 2>/dev/null | head -3
python3.13 -c "import sys; print('err', file=sys.stderr)" 2> err.log
echo "hello" > out.txt
echo "again" >> out.txt
Redirection operators inside quotes are kept as literal characters.
Pipelines
PySH connects each stage with a real OS pipe and closes the parent's duplicate handles after the child is spawned, so neither side deadlocks.
ls -la | head -3
apt list --upgradable 2>/dev/null | grep -c "/"
Variables
NAME=world # local shell variable
export GREETING=hi # exported environment variable
echo "$GREETING, $NAME"
Local variables shadow environment variables when expanded. Single quotes suppress expansion; double quotes do not.
~/.pyshrc
If ~/.pyshrc exists at startup, PySH executes it line by line through the
normal command path. Blank lines and lines starting with # are ignored.
You can also re-source it at any time:
source ~/.pyshrc
Example ~/.pyshrc
export EDITOR="nano"
export PAGER="less"
export LANG="pl_PL.UTF-8"
export PYTHONDONTWRITEBYTECODE="1"
alias ll="ls -la --color=auto -F"
alias ls="ls --color=auto -F"
alias grep="grep --color=auto"
alias rm="rm -i"
alias cp="cp -i"
alias mv="mv -i"
alias df="df -h"
alias free="free -h"
alias python="python3.13"
alias pip="pip3.13"
echo "🐍 PySH 0.1.1 | Python 3.13+"
echo "🐧 Debian ready"
echo "💡 Supported: && || ; | > >> < 2> 2>> &> &>> source alias export cd"
A failing line is reported on stderr and the next line is still executed.
Tab completion
Tab completes aliases and builtins for the first word, and filesystem
paths for any word. Inaccessible directories are silently skipped.
Testing and quality gates
pytest -q
ruff check src tests
python -m build
twine check dist/*
The project ships with unit tests for the parser, the redirection module, the rc loader and the shell itself.
Publishing
This repository is configured for PyPI Trusted Publishing via GitHub
Actions. See .github/workflows/publish.yml —
it uses pypa/gh-action-pypi-publish@release/v1 with id-token: write and
the pypi environment. Tagging a release on GitHub publishes the build.
Do not publish from a developer machine; let the workflow do it.
Target platform
- Primary target: Debian 13 with Python 3.13+.
- Should work on any POSIX system with a working
subprocessandreadline, but only Debian 13 is regularly validated.
License
PySH is distributed under the GNU General Public License v3.0 or later
(GPL-3.0-or-later). See LICENSE for the full text.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pysh_shell-0.1.1.tar.gz.
File metadata
- Download URL: pysh_shell-0.1.1.tar.gz
- Upload date:
- Size: 28.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
30a5c321b688340d909d0e937b2d38d5e2114b1d9a0df37468d2f469f6c4e1de
|
|
| MD5 |
2242c27feb08eed535c7e7ba98dae3b6
|
|
| BLAKE2b-256 |
d5197391ea4350d6ebb7f62096868090cebe0062336841e33293d3ce34b136de
|
Provenance
The following attestation bundles were made for pysh_shell-0.1.1.tar.gz:
Publisher:
publish.yml on SSobol77/pysh
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pysh_shell-0.1.1.tar.gz -
Subject digest:
30a5c321b688340d909d0e937b2d38d5e2114b1d9a0df37468d2f469f6c4e1de - Sigstore transparency entry: 1621300302
- Sigstore integration time:
-
Permalink:
SSobol77/pysh@ef6b4f2b9e62a2f054f3d62d7d642a16906bae57 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/SSobol77
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ef6b4f2b9e62a2f054f3d62d7d642a16906bae57 -
Trigger Event:
release
-
Statement type:
File details
Details for the file pysh_shell-0.1.1-py3-none-any.whl.
File metadata
- Download URL: pysh_shell-0.1.1-py3-none-any.whl
- Upload date:
- Size: 29.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9f535f32d40b19ee1de1d5e5d30728f22fef3fa4cf777a704470757f2c233cd
|
|
| MD5 |
4ffca7cfca7bb9f0bd830927cb447eb1
|
|
| BLAKE2b-256 |
06fecc21351c805c6dd8c96f20e76cada3676063e880a37df2595af5acb089f8
|
Provenance
The following attestation bundles were made for pysh_shell-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on SSobol77/pysh
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pysh_shell-0.1.1-py3-none-any.whl -
Subject digest:
e9f535f32d40b19ee1de1d5e5d30728f22fef3fa4cf777a704470757f2c233cd - Sigstore transparency entry: 1621300447
- Sigstore integration time:
-
Permalink:
SSobol77/pysh@ef6b4f2b9e62a2f054f3d62d7d642a16906bae57 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/SSobol77
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ef6b4f2b9e62a2f054f3d62d7d642a16906bae57 -
Trigger Event:
release
-
Statement type: