.. image:: https://readthedocs.org/projects/plumbum/badge/
:target: https://plumbum.readthedocs.io/en/latest/
:alt: Documentation Status
.. image:: https://github.com/tomerfiliba/plumbum/workflows/CI/badge.svg
:target: https://github.com/tomerfiliba/plumbum/actions
:alt: Build Status
.. image:: https://coveralls.io/repos/tomerfiliba/plumbum/badge.svg?branch=master&service=github
:target: https://coveralls.io/github/tomerfiliba/plumbum?branch=master
:alt: Coverage Status
.. image:: https://img.shields.io/pypi/v/plumbum.svg
:target: https://pypi.python.org/pypi/plumbum/
:alt: PyPI Status
.. image:: https://img.shields.io/pypi/pyversions/plumbum.svg
:target: https://pypi.python.org/pypi/plumbum/
:alt: PyPI Versions
.. image:: https://img.shields.io/conda/vn/conda-forge/plumbum.svg
:target: https://github.com/conda-forge/plumbum-feedstock
:alt: Conda-Forge Badge
.. image:: https://img.shields.io/pypi/l/plumbum.svg
:target: https://pypi.python.org/pypi/plumbum/
:alt: PyPI License
.. image:: https://badges.gitter.im/plumbumpy/Lobby.svg
:alt: Join the chat at https://gitter.im/plumbumpy/Lobby
:target: https://gitter.im/plumbumpy/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:alt: Code styled with Black
:target: https://github.com/psf/black
Plumbum: Shell Combinators
==========================
Ever wished the compactness of shell scripts be put into a **real** programming language?
Say hello to *Plumbum Shell Combinators*. Plumbum (Latin for *lead*, which was used to create
pipes back in the day) is a small yet feature-rich library for shell script-like programs in Python.
The motto of the library is **"Never write shell scripts again"**, and thus it attempts to mimic
the **shell syntax** ("shell combinators") where it makes sense, while keeping it all **Pythonic
and cross-platform**.
Apart from shell-like syntax and handy shortcuts, the library provides local and remote command
execution (over SSH), local and remote file-system paths, easy working-directory and environment
manipulation, and a programmatic Command-Line Interface (CLI) application toolkit.
Now let's see some code!
*This is only a teaser; the full documentation can be found at*
`Read the Docs <https://plumbum.readthedocs.io>`_
Cheat Sheet
-----------
Basics
******
.. code-block:: python
>>> from plumbum import local
>>> local.cmd.ls
LocalCommand(/bin/ls)
>>> local.cmd.ls()
'build.py\nCHANGELOG.rst\nconda.recipe\nCONTRIBUTING.rst\ndocs\nexamples\nexperiments\nLICENSE\nMANIFEST.in\nPipfile\nplumbum\nplumbum.egg-info\npytest.ini\nREADME.rst\nsetup.cfg\nsetup.py\ntests\ntranslations.py\n'
>>> notepad = local["c:\\windows\\notepad.exe"]
>>> notepad() # Notepad window pops up
'' # Notepad window is closed by user, command returns
In the example above, you can use ``local["ls"]`` if you have an unusually named executable or a full path to an executable. The ``local`` object represents your local machine. As you'll see, Plumbum also provides remote machines that use the same API!
You can also use ``from plumbum.cmd import ls`` as well for accessing programs in the ``PATH``.
Piping
******
.. code-block:: python
>>> from plumbum.cmd import ls, grep, wc
>>> chain = ls["-a"] | grep["-v", r"\.py"] | wc["-l"]
>>> print(chain)
/bin/ls -a | /bin/grep -v '\.py' | /usr/bin/wc -l
>>> chain()
'27\n'
Redirection
***********
.. code-block:: python
>>> from plumbum.cmd import cat, head
>>> ((cat < "setup.py") | head["-n", 4])()
'#!/usr/bin/env python3\nimport os\n\ntry:\n'
>>> (ls["-a"] > "file.list")()
''
>>> (cat["file.list"] | wc["-l"])()
'31\n'
Working-directory manipulation
******************************
.. code-block:: python
>>> local.cwd
<LocalWorkdir /home/tomer/workspace/plumbum>
>>> with local.cwd(local.cwd / "docs"):
... chain()
...
'22\n'
Foreground and background execution
***********************************
.. code-block:: python
>>> from plumbum import FG, BG
>>> (ls["-a"] | grep[r"\.py"]) & FG # The output is printed to stdout directly
build.py
setup.py
translations.py
>>> (ls["-a"] | grep[r"\.py"]) & BG # The process runs "in the background"
<Future ['/bin/grep', '\\.py'] (running)>
Command nesting
***************
.. code-block:: python
>>> from plumbum.cmd import sudo, ifconfig
>>> print(sudo[ifconfig["-a"]])
/usr/bin/sudo /sbin/ifconfig -a
>>> (sudo[ifconfig["-a"]] | grep["-i", "loop"]) & FG
lo Link encap:Local Loopback
UP LOOPBACK RUNNING MTU:16436 Metric:1
Remote commands (over SSH)
**************************
Supports `openSSH <http://www.openssh.org/>`_-compatible clients,
`PuTTY <http://www.chiark.greenend.org.uk/~sgtatham/putty/>`_ (on Windows)
and `Paramiko <https://github.com/paramiko/paramiko/>`_ (a pure-Python implementation of SSH2)
.. code-block:: python
>>> from plumbum import SshMachine
>>> remote = SshMachine("somehost", user = "john", keyfile = "/path/to/idrsa")
>>> r_ls = remote["ls"]
>>> with remote.cwd("/lib"):
... (r_ls | grep["0.so.0"])()
...
'libusb-1.0.so.0\nlibusb-1.0.so.0.0.0\n'
CLI applications
****************
.. code-block:: python
import logging
from plumbum import cli
class MyCompiler(cli.Application):
verbose = cli.Flag(["-v", "--verbose"], help = "Enable verbose mode")
include_dirs = cli.SwitchAttr("-I", list = True, help = "Specify include directories")
@cli.switch("--loglevel", int)
def set_log_level(self, level):
"""Sets the log-level of the logger"""
logging.root.setLevel(level)
def main(self, *srcfiles):
print("Verbose:", self.verbose)
print("Include dirs:", self.include_dirs)
print("Compiling:", srcfiles)
if __name__ == "__main__":
MyCompiler.run()
Sample output
+++++++++++++
::
$ python3 simple_cli.py -v -I foo/bar -Ispam/eggs x.cpp y.cpp z.cpp
Verbose: True
Include dirs: ['foo/bar', 'spam/eggs']
Compiling: ('x.cpp', 'y.cpp', 'z.cpp')
Colors and Styles
-----------------
.. code-block:: python
from plumbum import colors
with colors.red:
print("This library provides safe, flexible color access.")
print(colors.bold | "(and styles in general)", "are easy!")
print("The simple 16 colors or",
colors.orchid & colors.underline | '256 named colors,',
colors.rgb(18, 146, 64) | "or full rgb colors",
'can be used.')
print("Unsafe " + colors.bg.dark_khaki + "color access" + colors.bg.reset + " is available too.")
Raw data
{
"_id": null,
"home_page": null,
"name": "plumbum",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "cli, color, execution, local, path, pipe, popen, process, remote, shell, ssh",
"author": null,
"author_email": "Tomer Filiba <tomerfiliba@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/dc/c8/11a5f792704b70f071a3dbc329105a98e9cc8d25daaf09f733c44eb0ef8e/plumbum-1.10.0.tar.gz",
"platform": null,
"description": ".. image:: https://readthedocs.org/projects/plumbum/badge/\n :target: https://plumbum.readthedocs.io/en/latest/\n :alt: Documentation Status\n.. image:: https://github.com/tomerfiliba/plumbum/workflows/CI/badge.svg\n :target: https://github.com/tomerfiliba/plumbum/actions\n :alt: Build Status\n.. image:: https://coveralls.io/repos/tomerfiliba/plumbum/badge.svg?branch=master&service=github\n :target: https://coveralls.io/github/tomerfiliba/plumbum?branch=master\n :alt: Coverage Status\n.. image:: https://img.shields.io/pypi/v/plumbum.svg\n :target: https://pypi.python.org/pypi/plumbum/\n :alt: PyPI Status\n.. image:: https://img.shields.io/pypi/pyversions/plumbum.svg\n :target: https://pypi.python.org/pypi/plumbum/\n :alt: PyPI Versions\n.. image:: https://img.shields.io/conda/vn/conda-forge/plumbum.svg\n :target: https://github.com/conda-forge/plumbum-feedstock\n :alt: Conda-Forge Badge\n.. image:: https://img.shields.io/pypi/l/plumbum.svg\n :target: https://pypi.python.org/pypi/plumbum/\n :alt: PyPI License\n.. image:: https://badges.gitter.im/plumbumpy/Lobby.svg\n :alt: Join the chat at https://gitter.im/plumbumpy/Lobby\n :target: https://gitter.im/plumbumpy/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n :alt: Code styled with Black\n :target: https://github.com/psf/black\n\n\nPlumbum: Shell Combinators\n==========================\n\nEver wished the compactness of shell scripts be put into a **real** programming language?\nSay hello to *Plumbum Shell Combinators*. Plumbum (Latin for *lead*, which was used to create\npipes back in the day) is a small yet feature-rich library for shell script-like programs in Python.\nThe motto of the library is **\"Never write shell scripts again\"**, and thus it attempts to mimic\nthe **shell syntax** (\"shell combinators\") where it makes sense, while keeping it all **Pythonic\nand cross-platform**.\n\nApart from shell-like syntax and handy shortcuts, the library provides local and remote command\nexecution (over SSH), local and remote file-system paths, easy working-directory and environment\nmanipulation, and a programmatic Command-Line Interface (CLI) application toolkit.\nNow let's see some code!\n\n*This is only a teaser; the full documentation can be found at*\n`Read the Docs <https://plumbum.readthedocs.io>`_\n\nCheat Sheet\n-----------\n\nBasics\n******\n\n.. code-block:: python\n\n >>> from plumbum import local\n >>> local.cmd.ls\n LocalCommand(/bin/ls)\n >>> local.cmd.ls()\n 'build.py\\nCHANGELOG.rst\\nconda.recipe\\nCONTRIBUTING.rst\\ndocs\\nexamples\\nexperiments\\nLICENSE\\nMANIFEST.in\\nPipfile\\nplumbum\\nplumbum.egg-info\\npytest.ini\\nREADME.rst\\nsetup.cfg\\nsetup.py\\ntests\\ntranslations.py\\n'\n >>> notepad = local[\"c:\\\\windows\\\\notepad.exe\"]\n >>> notepad() # Notepad window pops up\n '' # Notepad window is closed by user, command returns\n\nIn the example above, you can use ``local[\"ls\"]`` if you have an unusually named executable or a full path to an executable. The ``local`` object represents your local machine. As you'll see, Plumbum also provides remote machines that use the same API!\nYou can also use ``from plumbum.cmd import ls`` as well for accessing programs in the ``PATH``.\n\nPiping\n******\n\n.. code-block:: python\n\n >>> from plumbum.cmd import ls, grep, wc\n >>> chain = ls[\"-a\"] | grep[\"-v\", r\"\\.py\"] | wc[\"-l\"]\n >>> print(chain)\n /bin/ls -a | /bin/grep -v '\\.py' | /usr/bin/wc -l\n >>> chain()\n '27\\n'\n\nRedirection\n***********\n\n.. code-block:: python\n\n >>> from plumbum.cmd import cat, head\n >>> ((cat < \"setup.py\") | head[\"-n\", 4])()\n '#!/usr/bin/env python3\\nimport os\\n\\ntry:\\n'\n >>> (ls[\"-a\"] > \"file.list\")()\n ''\n >>> (cat[\"file.list\"] | wc[\"-l\"])()\n '31\\n'\n\nWorking-directory manipulation\n******************************\n\n.. code-block:: python\n\n >>> local.cwd\n <LocalWorkdir /home/tomer/workspace/plumbum>\n >>> with local.cwd(local.cwd / \"docs\"):\n ... chain()\n ...\n '22\\n'\n\nForeground and background execution\n***********************************\n\n.. code-block:: python\n\n >>> from plumbum import FG, BG\n >>> (ls[\"-a\"] | grep[r\"\\.py\"]) & FG # The output is printed to stdout directly\n build.py\n setup.py\n translations.py\n >>> (ls[\"-a\"] | grep[r\"\\.py\"]) & BG # The process runs \"in the background\"\n <Future ['/bin/grep', '\\\\.py'] (running)>\n\nCommand nesting\n***************\n\n.. code-block:: python\n\n >>> from plumbum.cmd import sudo, ifconfig\n >>> print(sudo[ifconfig[\"-a\"]])\n /usr/bin/sudo /sbin/ifconfig -a\n >>> (sudo[ifconfig[\"-a\"]] | grep[\"-i\", \"loop\"]) & FG\n lo Link encap:Local Loopback\n UP LOOPBACK RUNNING MTU:16436 Metric:1\n\nRemote commands (over SSH)\n**************************\n\nSupports `openSSH <http://www.openssh.org/>`_-compatible clients,\n`PuTTY <http://www.chiark.greenend.org.uk/~sgtatham/putty/>`_ (on Windows)\nand `Paramiko <https://github.com/paramiko/paramiko/>`_ (a pure-Python implementation of SSH2)\n\n.. code-block:: python\n\n >>> from plumbum import SshMachine\n >>> remote = SshMachine(\"somehost\", user = \"john\", keyfile = \"/path/to/idrsa\")\n >>> r_ls = remote[\"ls\"]\n >>> with remote.cwd(\"/lib\"):\n ... (r_ls | grep[\"0.so.0\"])()\n ...\n 'libusb-1.0.so.0\\nlibusb-1.0.so.0.0.0\\n'\n\nCLI applications\n****************\n\n.. code-block:: python\n\n import logging\n from plumbum import cli\n\n class MyCompiler(cli.Application):\n verbose = cli.Flag([\"-v\", \"--verbose\"], help = \"Enable verbose mode\")\n include_dirs = cli.SwitchAttr(\"-I\", list = True, help = \"Specify include directories\")\n\n @cli.switch(\"--loglevel\", int)\n def set_log_level(self, level):\n \"\"\"Sets the log-level of the logger\"\"\"\n logging.root.setLevel(level)\n\n def main(self, *srcfiles):\n print(\"Verbose:\", self.verbose)\n print(\"Include dirs:\", self.include_dirs)\n print(\"Compiling:\", srcfiles)\n\n if __name__ == \"__main__\":\n MyCompiler.run()\n\nSample output\n+++++++++++++\n\n::\n\n $ python3 simple_cli.py -v -I foo/bar -Ispam/eggs x.cpp y.cpp z.cpp\n Verbose: True\n Include dirs: ['foo/bar', 'spam/eggs']\n Compiling: ('x.cpp', 'y.cpp', 'z.cpp')\n\nColors and Styles\n-----------------\n\n.. code-block:: python\n\n from plumbum import colors\n with colors.red:\n print(\"This library provides safe, flexible color access.\")\n print(colors.bold | \"(and styles in general)\", \"are easy!\")\n print(\"The simple 16 colors or\",\n colors.orchid & colors.underline | '256 named colors,',\n colors.rgb(18, 146, 64) | \"or full rgb colors\",\n 'can be used.')\n print(\"Unsafe \" + colors.bg.dark_khaki + \"color access\" + colors.bg.reset + \" is available too.\")\n",
"bugtrack_url": null,
"license": null,
"summary": "Plumbum: shell combinators library",
"version": "1.10.0",
"project_urls": {
"Bug Tracker": "https://github.com/tomerfiliba/plumbum/issues",
"Changelog": "https://plumbum.readthedocs.io/en/latest/changelog.html",
"Cheatsheet": "https://plumbum.readthedocs.io/en/latest/quickref.html",
"Documentation": "https://plumbum.readthedocs.io/",
"Homepage": "https://github.com/tomerfiliba/plumbum"
},
"split_keywords": [
"cli",
" color",
" execution",
" local",
" path",
" pipe",
" popen",
" process",
" remote",
" shell",
" ssh"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "79ad45312df6b63ba64ea35b8d8f5f0c577aac16e6b416eafe8e1cb34e03f9a7",
"md5": "3bfe2bd189d6f9af8ce1adb9c116aad3",
"sha256": "9583d737ac901c474d99d030e4d5eec4c4e6d2d7417b1cf49728cf3be34f6dc8"
},
"downloads": -1,
"filename": "plumbum-1.10.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "3bfe2bd189d6f9af8ce1adb9c116aad3",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 127383,
"upload_time": "2025-10-31T05:02:47",
"upload_time_iso_8601": "2025-10-31T05:02:47.002275Z",
"url": "https://files.pythonhosted.org/packages/79/ad/45312df6b63ba64ea35b8d8f5f0c577aac16e6b416eafe8e1cb34e03f9a7/plumbum-1.10.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "dcc811a5f792704b70f071a3dbc329105a98e9cc8d25daaf09f733c44eb0ef8e",
"md5": "0ecf9eed914a2d5b0b80f96132d95a97",
"sha256": "f8cbf0ecec0b73ff4e349398b65112a9e3f9300e7dc019001217dcc148d5c97c"
},
"downloads": -1,
"filename": "plumbum-1.10.0.tar.gz",
"has_sig": false,
"md5_digest": "0ecf9eed914a2d5b0b80f96132d95a97",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 320039,
"upload_time": "2025-10-31T05:02:48",
"upload_time_iso_8601": "2025-10-31T05:02:48.697033Z",
"url": "https://files.pythonhosted.org/packages/dc/c8/11a5f792704b70f071a3dbc329105a98e9cc8d25daaf09f733c44eb0ef8e/plumbum-1.10.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-31 05:02:48",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "tomerfiliba",
"github_project": "plumbum",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "plumbum"
}