Python Plumbum 简介：用 Python 来写脚本
Shell
![](/data/attachment/album/201803/22/101111fawijaevfv3d7e3l.jpg)


### Plumbum：Shell 组合器


你是否曾希望将 shell 脚本紧凑地融入到**真正**的编程语言里面？ 那么可以了解下 Plumbum Shell 组合器。Plumbum （lead 的拉丁语，以前用来制作管道）是一个小型但功能丰富的类库，用于以 Python 进行类似 shell 脚本编程。该库的理念是 “**永远不要再写 shell 脚本**”，因此它试图合理地模仿 shell 语法（shell 组合器），同时保持 **Python 特性和跨平台**。


除了[类似 shell 的语法](https://plumbum.readthedocs.io/en/latest/local_commands.html#guide-local-commands)和[便捷的快捷方式](https://plumbum.readthedocs.io/en/latest/utils.html#guide-utils)之外，该库还提供本地和[远程](https://plumbum.readthedocs.io/en/latest/remote.html#guide-remote-commands)命令执行（通过 SSH）、本地和远程文件系统[路径](https://plumbum.readthedocs.io/en/latest/paths.html#guide-paths)、简单的工作目录和环境[操作](https://plumbum.readthedocs.io/en/latest/local_machine.html#guide-local-machine)、快捷访问 ANSI 颜色，以及[编程命令行接口（CLI）](https://plumbum.readthedocs.io/en/latest/cli.html#guide-cli)应用程序工具包。现在让我们看一些代码！


其最新版本 1.6.6 发布于 2018 年 2 月 12 日。


### 快捷使用指南


#### 


#### 基本使用



```
>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> ls()
u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
>>> notepad = local["c:\\windows\\notepad.exe"]
>>> notepad()                                   # Notepad window pops up
u''                                             # Notepad window is closed by user, command returns

```

不需要为每个你想使用的命令写 `xxx = local["xxx"]`，你可以[导入命令行](https://plumbum.readthedocs.io/en/latest/local_commands.html#import-hack)：



```
>>> from plumbum.cmd import grep, wc, cat, head
>>> grep
LocalCommand(<LocalPath /bin/grep>)

```

参见[本地命令行](https://plumbum.readthedocs.io/en/latest/local_commands.html#guide-local-commands) 。


#### 管道



```
>>> chain = ls["-a"] | grep["-v", "\\.py"] | wc["-l"]
>>> print chain
/bin/ls -a | /bin/grep -v '\.py' | /usr/bin/wc -l
>>> chain()
u'13\n'

```

参见[管道](https://plumbum.readthedocs.io/en/latest/local_commands.html#guide-local-commands-pipelining)。


#### 重定向



```
>>> ((cat < "setup.py") | head["-n", 4])()
u'#!/usr/bin/env python\nimport os\n\ntry:\n'
>>> (ls["-a"] > "file.list")()
u''
>>> (cat["file.list"] | wc["-l"])()
u'17\n'

```

参见[输入/输出重定向](https://plumbum.readthedocs.io/en/latest/local_commands.html#guide-local-commands-redir)。


#### 工作目录操作



```
>>> local.cwd
<Workdir /home/tomer/workspace/plumbum>
>>> with local.cwd(local.cwd / "docs"):
...     chain()
...
u'15\n'

```

参见[路径](https://plumbum.readthedocs.io/en/latest/paths.html#guide-paths)和[本地对象](https://plumbum.readthedocs.io/en/latest/local_machine.html#guide-local-machine) 。


#### 前台后和后台执行



```
>>> from plumbum import FG, BG
>>> (ls["-a"] | grep["\\.py"]) & FG         # The output is printed to stdout directly
build.py
.pydevproject
setup.py
>>> (ls["-a"] | grep["\\.py"]) & BG         # The process runs "in the background"
<Future ['/bin/grep', '\\.py'] (running)>

```

参见[前台和后台](https://plumbum.readthedocs.io/en/latest/local_commands.html#guide-local-commands-bgfg)。


#### 命令行嵌套



```
>>> from plumbum.cmd import sudo
>>> 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

```

参见[命令行嵌套](https://plumbum.readthedocs.io/en/latest/local_commands.html#guide-local-commands-nesting)。


#### 远程命令（通过 SSH）



```
>>> 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"])()
...
u'libusb-1.0.so.0\nlibusb-1.0.so.0.0.0\n'

```

参见[远程](https://plumbum.readthedocs.io/en/latest/remote.html#guide-remote)。


#### CLI 应用程序



```
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()

```

输出样例：



```
$ python 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')

```

参见[命令行应用程序](https://plumbum.readthedocs.io/en/latest/cli.html#guide-cli)。


#### 颜色和风格



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

```

输出样例：



```
This library provides safe color access.
Color (and styles in general) are easy!
The simple 16 colors, 256 named colors, or full hex colors can be used.
Unsafe color access is available too.

```

参见[颜色](https://plumbum.readthedocs.io/en/latest/colors.html#guide-colors)。


### 开发和安装


该库在 [Github](https://github.com/tomerfiliba/plumbum) 上开发，非常乐意接受来自用户的[补丁](https://help.github.com/send-pull-requests/)。请使用 GitHub 的内置 [issue 跟踪器](https://github.com/tomerfiliba/plumbum/issues)报告您遇到的任何问题或提出功能上的需求。该库在 [IMIT 许可](https://github.com/tomerfiliba/plumbum/blob/master/LICENSE)下发布。


#### 要求


Plumbum 支持 Python 2.6-3.6 和 PyPy，并且通过 [Travis CI](https://travis-ci.org/tomerfiliba/plumbum) 和 [Appveyor](https://ci.appveyor.com/project/HenrySchreiner/plumbum/branch/master) 持续地在 Linux，Mac 和 Windows 机器上测试。Plumbum 在任何类 Unix 的机器都应该可以正常工作，但是在 Windows 上，你也许需要安装一个合适的 [coreutils](https://www.wikiwand.com/en/Coreutils) 环境并把其加入到你的`PATH`环境变量中。我推荐 [mingw](http://mingw.org/)（与 [Windows Git](http://msysgit.github.io/) 捆绑在一起），但是 [cygwin](http://www.cygwin.com/) 应该也可以。如果你仅仅是使用 Plumbum 代替 Popen 来运行 Windows 程序，那么就不需要 Unix 工具了。 注意远程命令的执行，你需要一个 openSHH 兼容的客户端（同样与 Windows Git 捆绑在一起）和一个 bash 兼容的 shell，也需要在主机上有一个 coreutils 环境。


#### 下载


你可以在 [**Python Package Index**](https://pypi.python.org/pypi/plumbum#downloads) （多种格式）下载该库，或者直接运行 `pip install plumbum`。如果你使用 Anaconda，你可以使用 `conda install -c conda-forge plumbum` 从 `conda-forge` 通道获取。


### 用户指南


用户指南涵盖了 Plumbum 大部分功能，拥有大量的代码片段，你可以不用花多少时间即可开始使用。该指南逐渐介绍概念和"语法"，因此推荐你按照顺序阅读。一个[**有效的快速参考指南**](https://plumbum.readthedocs.io/en/latest/quickref.html#guide-quickref)。 *略。。。*


#### 


### 关于


Plumburn 最初的目的是让本地和远程程序轻松地执行，假设没有比老的 ssh 更时髦的东西了。在此基础上，设计了一个文件系统抽象层，以便能够无缝地处理本地和远程文件。 我有这个想法一段时间了，直到我必须要个给我当前工作的项目写一个构建脚本，我决定使用 shell 脚本，现在是实现它的时候了。Plumbum 诞生自 `Path` 类的片段和我为 [**RPyC**](http://rpyc.readthedocs.io/en/latest/) 写的 `SshContext` 和 `SshTunnel` 类。`Path` 类是我为前面说的构建系统写的。当我将两者与 *shell 组合器*（因为 shell 脚本在这里确实有优势）组合在一起时，奇迹就发生了，便产生了Plumbun。


### 致谢


该项目受到了 [**Andrew Moffat**](https://github.com/amoffat) 的 **PBS**（现在被称作 [**sh**](http://amoffat.github.io/sh/)）启发，并且借用了他的一些思想（即像函数一样看待程序，导入命令行的技巧）。然而我感觉在 PBS 中有太多的神秘的东西，当我编写类 shell 程序时，语法不是我想要的。关于这个问题我联系了 Andrew，但是他想让 PBS 保持这种状态。除此之外，两个库走不同的方向，Plumbum 试图提供一种更合理的方法。


Plumbum 也向 [**Rotem Yaari**](https://github.com/vmalloc/) 致敬，他为特定的目的建议了一个代号为 `pyplatform` 的库，但是尚未实现过。


OK
# Plumbum: Shell Combinators and More[¶](#plumbum-shell-combinators-and-more)

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](local_commands.html#guide-local-commands) and [handy shortcuts](utils.html#guide-utils),
the library provides local and [remote](remote.html#guide-remote-commands) command execution (over SSH),
local and remote file-system [paths](paths.html#guide-paths), easy working-directory and
environment [manipulation](local_machine.html#guide-local-machine), quick access to ANSI [colors](colors.html#guide-colors), and a programmatic
[Command-Line Interface (CLI)](cli.html#guide-cli) application toolkit. Now let’s see some code!

# News[¶](#news)

**2023.10.05**: Version 1.9.0 released with Python 3.8-3.13 support, and some small fixes.**2024.04.29**: Version 1.8.3 released with some small fixes, final version to support Python 3.6 and 3.7.**2023.05.30**: Version 1.8.2 released with a PyPI metadata fix, Python 3.12b1 testing, and a bit more typing.**2023.01.01**: Version 1.8.1 released with hatchling replacing setuptools for the build system, and support for Path objects in local.**2022.10.05**: Version 1.8.0 released with`NO_COLOR`

/`FORCE_COLOR`

,`all_markers`

& future annotations for the CLI, some command enhancements, & Python 3.11 testing.**2021.12.23**: Version 1.7.2 released with very minor fixes, final version to support Python 2.7 and 3.5.**2021.11.23**: Version 1.7.1 released with a few features like reverse tunnels, color group titles, and a glob path fix. Better Python 3.10 support.**2021.02.08**: Version 1.7.0 released with a few new features like`.with_cwd`

, some useful bugfixes, and lots of cleanup.**2020.03.23**: Version 1.6.9 released with several Path fixes, final version to support Python 2.6.**2019.10.30**: Version 1.6.8 released with`local.cmd`

, a few command updates,`Set`

improvements, and`TypedEnv`

.**2018.08.10**: Version 1.6.7 released with several minor additions, mostly to CLI apps, and`run_*`

modifiers added.**2018.02.12**: Version 1.6.6 released with one more critical bugfix for a error message regression in 1.6.5.**2017.12.29**: Version 1.6.5 released with mostly bugfixes, including a critical one that could break pip installs on some platforms. English cli apps now load as fast as before the localization update.**2017.11.27**: Version 1.6.4 released with new CLI localization support. Several bugfixes and better pathlib compatibility, along with better separation between Plumbum’s internal packages.**2016.12.31**: Version 1.6.3 released to provide Python 3.6 compatibility. Mostly bugfixes, several smaller improvements to paths, and a provisional config parser added.**2016.12.3**: Version 1.6.2 is now available through[conda-forge](https://conda-forge.github.io), as well.**2016.6.25**: Version 1.6.2 released. This is mostly a bug fix release, but a few new features are included. Modifiers allow some new arguments, and`Progress`

is improved. Better support for SunOS and other OS’s.**2015.12.18**: Version 1.6.1 released. The release mostly contains smaller fixes for CLI, 2.6/3.5 support, and colors. PyTest is now used for tests, and Conda is supported.**2015.10.16**: Version 1.6.0 released. Highlights include Python 3.5 compatibility, the`plumbum.colors`

package,`Path`

becoming a subclass of`str`

and a host of bugfixes. Special thanks go to Henry for his efforts.**2015.07.17**: Version 1.5.0 released. This release brings a host of bug fixes, code cleanups and some experimental new features (be sure to check the changelog). Also, say hi to[Henry Schreiner](https://github.com/henryiii), who has joined as a member of the project.

# Cheat Sheet[¶](#cheat-sheet)

## Basics[¶](#basics)

```
>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> ls()
'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
>>> notepad = local["c:\\windows\\notepad.exe"]
>>> notepad() # Notepad window pops up
'' # Notepad window is closed by user, command returns
```

Instead of writing `xxx = local["xxx"]`

for every program you wish to use, you can
also [import commands](local_commands.html#import-hack):

```
>>> from plumbum.cmd import grep, wc, cat, head
>>> grep
LocalCommand(<LocalPath /bin/grep>)
```

Or, use the `local.cmd`

syntactic-sugar:

```
>>> local.cmd.ls
LocalCommand(<LocalPath /bin/ls>)
>>> local.cmd.ls()
'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
```

See [Local Commands](local_commands.html#guide-local-commands).

## Piping[¶](#piping)

```
>>> chain = ls["-a"] | grep["-v", "\\.py"] | wc["-l"]
>>> print(chain)
/bin/ls -a | /bin/grep -v '\.py' | /usr/bin/wc -l
>>> chain()
'13\n'
```

See [Pipelining](local_commands.html#guide-local-commands-pipelining).

## Redirection[¶](#redirection)

```
>>> ((cat < "setup.py") | head["-n", 4])()
'#!/usr/bin/env python3\nimport os\n\ntry:\n'
>>> (ls["-a"] > "file.list")()
''
>>> (cat["file.list"] | wc["-l"])()
'17\n'
```

## Working-directory manipulation[¶](#working-directory-manipulation)

```
>>> local.cwd
<Workdir /home/tomer/workspace/plumbum>
>>> with local.cwd(local.cwd / "docs"):
... chain()
...
'15\n'
```

A more explicit, and thread-safe way of running a command in a different directory is using the `.with_cwd()`

method:

```
.. code-block:: python
```

```
>>> ls_in_docs = local.cmd.ls.with_cwd("docs")
>>> ls_in_docs()
'api\nchangelog.rst\n_cheatsheet.rst\ncli.rst\ncolorlib.rst\n_color_list.html\ncolors.rst\nconf.py\nindex.rst\nlocal_commands.rst\nlocal_machine.rst\nmake.bat\nMakefile\n_news.rst\npaths.rst\nquickref.rst\nremote.rst\n_static\n_templates\ntyped_env.rst\nutils.rst\n'
```

See [Paths](paths.html#guide-paths) and [The Local Object](local_machine.html#guide-local-machine).

## Foreground and background execution[¶](#foreground-and-background-execution)

```
>>> from plumbum import FG, BG
>>> (ls["-a"] | grep["\\.py"]) & FG # The output is printed to stdout directly
build.py
.pydevproject
setup.py
>>> (ls["-a"] | grep["\\.py"]) & BG # The process runs "in the background"
<Future ['/bin/grep', '\\.py'] (running)>
```

## Command nesting[¶](#command-nesting)

```
>>> from plumbum.cmd import sudo
>>> 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
```

See [Command Nesting](local_commands.html#guide-local-commands-nesting).

## Remote commands (over SSH)[¶](#remote-commands-over-ssh)

Supports [openSSH](https://www.openssh.com/)-compatible clients,
[PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/) (on Windows)
and [Paramiko](https://github.com/paramiko/paramiko/) (a pure-Python implementation of SSH2):

```
>>> 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'
```

See [Remote](remote.html#guide-remote).

## CLI applications[¶](#cli-applications)

```
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[¶](#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[¶](#colors-and-styles)

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

### Sample output[¶](#id1)

```
```This library provides safe color access.
Color **(and styles in general)** are easy!
The simple 16 colors, 256 named colors, or full hex colors can be used.
Unsafe color access is available too.


See [Colors](colors.html#guide-colors).

# Development and Installation[¶](#development-and-installation)

The library is developed on [GitHub](https://github.com/tomerfiliba/plumbum), and will happily
accept [patches](https://docs.github.com/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) from users. Please use the GitHub’s
built-in [issue tracker](https://github.com/tomerfiliba/plumbum/issues) to report any problem
you encounter or to request features. The library is released under the permissive [MIT license](https://github.com/tomerfiliba/plumbum/blob/master/LICENSE).

## Requirements[¶](#requirements)

Plumbum supports **Python 3.6-3.10** and **PyPy** and is continually tested on
**Linux**, **Mac**, and **Windows** machines through [GitHub Actions](https://github.com/tomerfiliba/plumbum/actions). Any Unix-like machine
should work fine out of the box, but on Windows, you’ll probably want to
install a decent [coreutils](https://en.wikipedia.org/wiki/GNU_Core_Utilities/)
environment and add it to your `PATH`

, or use WSL(2). I can recommend [mingw](https://mingw.osdn.io/) (which comes bundled with [Git for Windows](https://gitforwindows.org/)), but [cygwin](http://www.cygwin.com/) should
work too. If you only wish to use Plumbum as a Popen-replacement to run Windows
programs, then there’s no need for the Unix tools.

Note that for remote command execution, an **openSSH-compatible** client is
required (also bundled with *Git for Windows*), and a `bash`

-compatible shell
and a coreutils environment is also expected on the host machine.

This project uses `setuptools`

to build wheels; and `setuptools_scm`

is
required for building SDists. These dependencies will be handled for you by PEP
518 compatible builders, like [build](https://github.com/pypa/build) and `pip 10+`

.

## Download[¶](#download)

You can **download** the library from the [Python Package Index](https://pypi.org/pypi/plumbum/#files) (in a variety of formats), or
run `pip install plumbum`

directly. If you use Anaconda, you can also get it
from the `conda-forge`

channel with `conda install -c conda-forge plumbum`

.

# User Guide[¶](#user-guide)

The user guide covers most of the features of Plumbum, with lots of code-snippets to get you
swimming in no time. It introduces the concepts and “syntax” gradually, so it’s recommended
you read it in order. A quick [reference guide is available](quickref.html#guide-quickref).

# API Reference[¶](#api-reference)

The API reference (generated from the *docstrings* within the library) covers all of the
exposed APIs of the library. Note that some “advanced” features and some function parameters are
missing from the guide, so you might want to consult with the API reference in these cases.

[Package plumbum.cli](api/cli.html)`ShowHelp`

`ShowHelpAll`

`ShowVersion`

`Application`

`SwitchError`

`PositionalArgumentsError`

`SwitchCombinationError`

`UnknownSwitch`

`MissingArgument`

`MissingMandatorySwitch`

`WrongArgumentType`

`SubcommandError`

`switch()`

`autoswitch()`

`SwitchAttr`

`Flag`

`CountOf`

`positional`

`Validator`

`Range`

`Set`

`Predicate`

[Terminal-related utilities](api/cli.html#terminal-related-utilities)`readline()`

`ask()`

`choose()`

`prompt()`

`get_terminal_size()`

`Progress`

[Terminal size utility](api/cli.html#terminal-size-utility)`get_terminal_size()`

[Progress bar](api/cli.html#progress-bar)`ProgressBase`

`Progress`

`ProgressIPy`

`ProgressAuto`


[Package plumbum.commands](api/commands.html)`iter_lines()`

`run_proc()`

`shquote()`

`RedirectionError`

`BaseCommand`

`Pipeline`

`BaseRedirection`

`BoundCommand`

`BoundEnvCommand`

`ConcreteCommand`

`StdinRedirection`

`StdoutRedirection`

`StderrRedirection`

`AppendingStdoutRedirection`

`StdinDataRedirection`

`Future`

`PipeToLoggerMixin`

`ProcessExecutionError`

`ProcessTimedOut`

`ProcessLineTimedOut`

`CommandNotFound`

`run_proc()`

`iter_lines()`


[Package plumbum.machines](api/machines.html)[Package plumbum.path](api/path.html)[Package plumbum.fs](api/fs.html)[Package plumbum.colors](api/colors.html)[Colorlib design](colorlib.html)

Note

The `local`

object is an instance of a `machine`

.

# About[¶](#about)

The original purpose of Plumbum was to enable local and remote program execution with ease, assuming nothing fancier than good-old SSH. On top of this, a file-system abstraction layer was devised, so that working with local and remote files would be seamless.

I’ve toyed with this idea for some time now, but it wasn’t until I had to write build scripts
for a project I’ve been working on that I decided I’ve had it with shell scripts and it’s time
to make it happen. Plumbum was born from the scraps of the `Path`

class, which I
wrote for the aforementioned build system, and the `SshContext`

and `SshTunnel`

classes
that I wrote for [RPyC](https://rpyc.readthedocs.io/). When I combined the two with *shell combinators*
(because shell scripts do have an edge there) the magic happened and here we are.

# Credits[¶](#credits)

The project has been inspired by **PBS** (now called [sh](http://sh.rtfd.org))
of [Andrew Moffat](https://github.com/amoffat),
and has borrowed some of his ideas (namely treating programs like functions and the
nice trick for importing commands). However, I felt there was too much magic going on in PBS,
and that the syntax wasn’t what I had in mind when I came to write shell-like programs.
I contacted Andrew about these issues, but he wanted to keep PBS this way. Other than that,
the two libraries go in different directions, where Plumbum attempts to provide a more
wholesome approach.

Plumbum also pays tribute to [Rotem Yaari](https://github.com/vmalloc/) who suggested a
library code-named `pyplatform`

for that very purpose, but which had never materialized.