Install & Compatibility
Where this runs
tested against v2.4.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.95 runs
installs and imports cleanly · install 0.0s · import 0.310s · 18.1MB
glibcpy 3.10–3.95 runs
installs and imports cleanly · install 1.7s · import 0.264s · 19MB
16MB installed
● package 16MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
sh
✓ import sh
Imports the main 'sh' object, from which system commands are accessed as attributes (e.g., sh.ls).
Command
✓ from sh import Command
Useful for explicitly calling commands not in PATH or with special characters, e.g., `cmd = Command('/usr/bin/ffmpeg')`.
ErrorReturnCode
✓ from sh import ErrorReturnCode_127
Specific error codes (e.g., ErrorReturnCode_1, ErrorReturnCode_127) are raised when a command exits with a non-zero status. Catch `sh.ErrorReturnCode` for a general handler.
bash
✓ from sh.contrib import bash
Introduced in 2.1.0 for improved Bash integration.
This quickstart demonstrates basic command execution, passing arguments, capturing output, handling non-zero exit codes, and piping commands. Replace `ls` and `python` with commands available on your system.
import sh
import os
# Get the current user
user = os.environ.get('USER', 'unknown_user')
print(f"Hello, {user}!")
# Run a simple command and capture output
output = sh.ls('-l', '/tmp')
print(f"\nls -l /tmp:\n{output}")
# Run a command with arguments
version_info = sh.python('-V')
print(f"\nPython version:\n{version_info}")
# Handle a non-zero exit code
try:
sh.false()
except sh.ErrorReturnCode_1 as e:
print(f"\nCaught expected error: {e.full_cmd}, Exit Code: {e.exit_code}")
# Pipe commands (similar to shell)
piped_output = sh.wc('-l', _in=sh.ls('-1'))
print(f"\nNumber of files in current directory: {piped_output.strip()}")
Debug
Known issues
breakingThe `sh` library is designed exclusively for Unix-like operating systems (Linux, macOS, BSDs). It relies on various Unix system calls and does not support Windows environments.fixUse `subprocess` module or alternative libraries for cross-platform compatibility, or ensure deployment on Unix-like systems only.
affects: All versions
breakingUpgrading from `sh` 1.x to 2.x involves significant breaking changes. Users are strongly advised to consult the `MIGRATION.md` file in the project's repository or PyPI page before upgrading.fixReview `MIGRATION.md` and adapt code as necessary to align with the 2.x API.
affects: 1.x to 2.x migration
gotchaWhen an executed command exits with a non-zero status code, `sh` raises an `sh.ErrorReturnCode_X` exception (where X is the exit code), rather than silently failing. This behavior must be explicitly handled with `try...except` blocks.fixWrap command calls that might return non-zero exit codes in `try...except sh.ErrorReturnCode` blocks to handle errors gracefully.
affects: All versions
gotchaPrior to version 2.2.2, using `async` commands in combination with `_return_cmd=True` could lead to unexpected behavior. Specifically, `await` on such a command might return `str(self)` instead of a `RunningCommand` object, and earlier versions (pre-2.2.1) had bugs where async commands with `return_cmd` did not raise exceptions correctly.fixUpgrade to `sh` 2.2.2 or later to ensure correct asynchronous behavior and error handling for commands using `_return_cmd=True`.
affects: <2.2.2
gotchaWhile `sh` provides a Pythonic wrapper, it directly executes underlying shell commands. This means many common shell footguns (e.g., issues with improper quoting, globbing, or special characters in filenames) can still affect your scripts.fixBe mindful of shell scripting best practices, especially concerning argument quoting and validation. Leverage `sh`'s list-based argument passing where possible, as it generally handles quoting automatically.
affects: All versions
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'sh'
The 'sh' library is not installed in the Python environment being used.
fixInstall the library using pip: `pip install sh`
sh.CommandNotFound: <command_name> not found
The external command specified (e.g., 'git', 'ls') is not found in the system's PATH environment variable.
fixEnsure the command is installed and its directory is included in your system's PATH, or provide the full path to the executable.
sh.ErrorReturnCode_N: <command_name> returned non-zero exit status N
The executed external command exited with a non-zero status code, signaling that it failed or encountered an error.
fixHandle the exception by wrapping the call in a `try...except sh.ErrorReturnCode` block, inspect `e.stderr` or `e.stdout` for details, or ensure the command's arguments are correct.
sh.TimeoutException: Timeout while running <command_name>
The external command took longer to execute than the specified `_timeout` duration.
fixIncrease the `_timeout` parameter when calling the `sh` command, or investigate why the command is taking too long to execute.
AttributeError: '_ShProc' object has no attribute 'splitlines'
The return value of an `sh` command is a `_ShProc` object, not a plain string, and string methods like `splitlines()` must be called after explicit conversion to `str` or `bytes`.
fixConvert the `_ShProc` object to a string using `str()` before calling string methods, for example: `str(sh.ls()).splitlines()` or `sh.ls().stdout.decode().splitlines()`.
Upgrade
Version history
2.4.0latest on PyPI · released Jul 25, 2026
Audit
Dependencies
pythonrequiredRequired Python version range