



  

shell 1.0.1 documentation

 [shell](index.html#document-index) 

 stable

 

* [shell Tutorial](index.html#document-tutorial)

* [Shell API](index.html#document-shell_api)

* [Testing shell](index.html#document-testing)

* [Contributing](index.html#document-contributing)

[shell](index.html#document-index)

* [Docs](index.html#document-index) »

* shell 1.0.1 documentation

* [Edit on GitHub](https://github.com/toastdriven/shell/blob/703307b6dc9a287133f6ac1881f231eed6b79506/docs/index.rst)

---

shell’s Documentation[¶](#shell-s-documentation "Permalink to this headline")

=============================================================================

“”“A better way to run shell commands in Python.”“”

Built because every time I go to use [subprocess](http://docs.python.org/2.7/library/subprocess.html), I spend more time in the

docs & futzing around than actually implementing what I’m trying to get done.

Philosophy[¶](#philosophy "Permalink to this headline")

-------------------------------------------------------

* Makes running commands more natural

* Assumes you care about the output/errors by default

* Covers the 80% case of running commands

* A nicer API

* Works on Linux/OS X (untested on Windows but might work?)

Contents:

### shell Tutorial[¶](#shell-tutorial "Permalink to this headline")

If you’ve ever tried to run a shell command in Python, you’re likely unhappy

about it. The `subprocess` module, while a huge & consistent step forward

over the previous ways Python shelled out, has a rather painful interface.

If you’re like me, you spent more time in the docs than you did writing working

code.

`shell` tries to fix this, by glossing over the warts in the `subprocess`

API & making running commands *easy*.

#### Installation[¶](#installation "Permalink to this headline")

If you’re developing in Python, you ought to be using [pip](http://www.pip-installer.org/en/latest/). Installing (from

your terminal) looks like:

```

$ pip install shell

```

#### Quickstart[¶](#quickstart "Permalink to this headline")

For the impatient:

```

>>> from shell import shell

>>> ls = shell('ls')

>>> for file in ls.output():

...     print file

'another.txt'

# Or if you need more control, the same code can be stated as...

>>> from shell import Shell

>>> sh = Shell()

>>> sh.run('ls')

>>> for file in sh.output():

...     print file

'another.txt'

```

#### Getting Started[¶](#getting-started "Permalink to this headline")

##### Importing[¶](#importing "Permalink to this headline")

The first thing you’ll need to do is import `shell`. You can either use

the easy functional version:

```

>>> from shell import shell

```

Or the class-based & extensible version:

```

>>> from shall import Shell

```

##### Your First Command[¶](#your-first-command "Permalink to this headline")

Running a basic command is simple. Simply hand the command you’d use at the

terminal off to `shell`:

```

>>> from shell import shell

>>> shell('touch hello\_world.txt')

# The class-based variant.

>>> from shall import Shell

>>> sh = Shell()

>>> sh.run('touch hello\_world.txt')

```

You should now have a `hello\_world.txt` file created in your current

directory.

##### Reading Output[¶](#reading-output "Permalink to this headline")

By default, `shell` captures output/errors from the command being run. You can

read the output & errors like so:

```

>>> from shell import shell

>>> sh = shell('ls /tmp')

# Your output from these calls will vary...

>>> sh.output()

[

 'hello.txt',

 'world.py',

]

>>> sh.errors()

[]

# The class-based variant.

>>> from shell import Shell

>>> sh = Shell()

>>> sh.run('ls /tmp')

>>> sh.output()

[

 'hello.txt',

 'world.py',

]

>>> sh.errors()

[]

```

You can also look at what the process ID was & the return code.:

```

>>> sh.pid

15172

>>> sh.code

0

```

Getting a `0` from `sh.code` means a process finished sucessfully. Higher

integer return values generally mean there was an error.

##### Interactive[¶](#interactive "Permalink to this headline")

If the command is interactive, you can send it input as well.:

```

>>> from shell import shell

>>> sh = shell('cat -u', has\_input=True)

>>> sh.write('Hello, world!')

>>> sh.output()

[

 'Hello, world!'

]

# The class-based variant.

>>> from shall import Shell

>>> sh = Shell(has\_input=True)

>>> sh.run('cat -u')

>>> sh.write('Hello, world!')

>>> sh.output()

[

 'Hello, world!'

]

```

Warning

You get one shot at sending input, after which the command will finish.

Using `shell` for advanced, multi-prompt shell commands is likely is not

a good option.

##### Chaining[¶](#chaining "Permalink to this headline")

You can also chain calls together, if that suits you.:

```

>>> from shell import shell

>>> shell('cat -u', has\_input=True).write('Hello, world!').output()

[

 'Hello, world!'

]

# The class-based variant.

>>> from shall import Shell

>>> Shell(has\_input=True).run('cat -u').write('Hello, world!').output()

[

 'Hello, world!'

]

```

##### Ignoring Large Output[¶](#ignoring-large-output "Permalink to this headline")

By default, `shell` captures all output/errors. If you have a command that

generates a large volume of output that you don’t care about, you can ignore

it like so.:

```

>>> from shell import shell

>>> sh = shell('run\_intensive\_command -v', record\_output=False, record\_errors=False)

>>> sh.code

0

# The class-based variant.

>>> from shall import Shell

>>> sh = Shell(record\_output=False, record\_errors=False)

>>> sh.run('run\_intensive\_command -v')

>>> sh.code

0

```

#### What Now?[¶](#what-now "Permalink to this headline")

If you need more advanced functionality, subclassing the `Shell` class is the

best place to start.

You can find more details about it in the [*Shell API*](index.html#document-shell_api).

### Shell API[¶](#shell-api "Permalink to this headline")

#### shell[¶](#module-shell "Permalink to this headline")

##### shell[¶](#id1 "Permalink to this headline")

A better way to run shell commands in Python.

If you just need to quickly run a command, you can use the `shell` shortcut

function:

```

>>> from shell import shell

>>> ls = shell('ls')

>>> for file in ls.output():

...     print file

'another.txt'

```

If you need to extend the behavior, you can also use the `Shell` object:

```

>>> from shell import Shell

>>> sh = Shell(has\_input=True)

>>> cat = sh.run('cat -u')

>>> cat.write('Hello, world!')

>>> cat.output()

['Hello, world!']

```

*exception* `shell.``CommandError`[¶](#shell.CommandError "Permalink to this definition")

Thrown when a command fails.

`error_code` *= 1*[¶](#shell.CommandError.error_code "Permalink to this definition")

*exception* `shell.``MissingCommandException`[¶](#shell.MissingCommandException "Permalink to this definition")

Thrown when no command was setup.

*class* `shell.``Shell`(*has\_input=False*, *record\_output=True*, *record\_errors=True*, *strip\_empty=True*)[¶](#shell.Shell "Permalink to this definition")

Handles executing commands & recording output.

Optionally accepts a `has\_input` parameter, which should be a boolean.

If set to `True`, the command will wait to execute until you call the

`Shell.write` method & send input. (Default: `False`)

Optionally accepts a `record\_output` parameter, which should be a boolean.

If set to `True`, the stdout from the command will be recorded.

(Default: `True`)

Optionally accepts a `record\_errors` parameter, which should be a boolean.

If set to `True`, the stderr from the command will be recorded.

(Default: `True`)

Optionally accepts a `strip\_empty` parameter, which should be a boolean.

If set to `True`, only non-empty lines from `Shell.output` or

`Shell.errors` will be returned. (Default: `True`)

`errors`(*raw=False*)[¶](#shell.Shell.errors "Permalink to this definition")

Returns the errors from running a command.

Optionally accepts a `raw` parameter, which should be a boolean. If

`raw` is set to `False`, you get an array of lines of errors. If

`raw` is set to `True`, the raw string of errors is returned.

(Default: `False`)

Example:

```

>>> from shell import Shell

>>> sh = Shell()

>>> sh.run('ls /there-s-no-way-anyone/has/this/directory/please')

>>> sh.errors()

[

 'ls /there-s-no-way-anyone/has/this/directory/please: No such file or directory'

]

```

`kill`()[¶](#shell.Shell.kill "Permalink to this definition")

Kills a given process.

Example:

```

>>> from shell import Shell

>>> sh = Shell()

>>> sh.run('some\_long\_running\_thing')

>>> sh.kill()

```

`output`(*raw=False*)[¶](#shell.Shell.output "Permalink to this definition")

Returns the output from running a command.

Optionally accepts a `raw` parameter, which should be a boolean. If

`raw` is set to `False`, you get an array of lines of output. If

`raw` is set to `True`, the raw string of output is returned.

(Default: `False`)

Example:

```

>>> from shell import Shell

>>> sh = Shell()

>>> sh.run('ls ~')

>>> sh.output()

[

 'hello.txt',

 'world.txt',

]

```

`run`(*command*)[¶](#shell.Shell.run "Permalink to this definition")

Runs a given command.

Requires a `command` parameter should be either a string command

(easier) or an array of arguments to send as the command (if you know

what you’re doing).

Returns the `Shell` instance.

Example:

```

>>> from shell import Shell

>>> sh = Shell()

>>> sh.run('ls- alh')

```

`write`(*the\_input*)[¶](#shell.Shell.write "Permalink to this definition")

If you’re working with an interactive process, sends that input to

the process.

This needs to be used in conjunction with the `has\_input=True`

parameter.

Requires a `the\_input` parameter, which should be a string of the

input to send to the command.

Returns the `Shell` instance.

Example:

```

>>> from shell import Shell

>>> sh = Shell(has\_input=True)

>>> sh.run('cat -u')

>>> sh.write('Hello world!')

```

*exception* `shell.``ShellException`[¶](#shell.ShellException "Permalink to this definition")

The base exception for all shell-related errors.

`shell.``shell`(*command*, *has\_input=False*, *record\_output=True*, *record\_errors=True*, *strip\_empty=True*)[¶](#shell.shell "Permalink to this definition")

A convenient shortcut for running commands.

Requires a `command` parameter should be either a string command

(easier) or an array of arguments to send as the command (if you know

what you’re doing).

Optionally accepts a `has\_input` parameter, which should be a boolean.

If set to `True`, the command will wait to execute until you call the

`Shell.write` method & send input. (Default: `False`)

Optionally accepts a `record\_output` parameter, which should be a boolean.

If set to `True`, the stdout from the command will be recorded.

(Default: `True`)

Optionally accepts a `record\_errors` parameter, which should be a boolean.

If set to `True`, the stderr from the command will be recorded.

(Default: `True`)

Optionally accepts a `strip\_empty` parameter, which should be a boolean.

If set to `True`, only non-empty lines from `Shell.output` or

`Shell.errors` will be returned. (Default: `True`)

Returns the `Shell` instance, which has been run with the given command.

Example:

```

>>> from shell import shell

>>> sh = shell('ls -alh \*py')

>>> sh.output()

['hello.py', 'world.py']

```

### Testing shell[¶](#testing-shell "Permalink to this headline")

`shell` maintains 100% passing tests at all times. That said, there are

undoubtedly bugs or odd configurations it doesn’t cover.

#### Setup[¶](#setup "Permalink to this headline")

Getting setup to run tests (Python 2) looks like:

```

$ git clone https://github.com/toastdriven/shell

$ cd shell

$ virtualenv env

$ . env/bin/activate

$ pip install mock==1.0.1

$ pip install nose==1.3.0

```

Once that’s setup, setting up for Python 3 looks like:

```

$ virtualenv -p python3 env3

$ . env3/bin/activate

$ pip install mock==1.0.1

$ pip install nose==1.3.0

```

#### Running the tests[¶](#running-the-tests "Permalink to this headline")

To run the tests, run the following:

```

$ nosetests -s tests.py

```

### Contributing[¶](#contributing "Permalink to this headline")

To contribute to `shell`, it must meet the following criteria:

* Has a failing test case (see `tests.py` & testing) without the fix

* Has a fix that matches existing style

* Has docstrings

* Adds to the documentation if the change is user-facing

* Is BSD-compatibly licensed

Please create fork on Github, clone your fork, create a new branch, make your

changes on that branch, push it back to Github & open a pull request.

Indices and tables[¶](#indices-and-tables "Permalink to this headline")

=======================================================================

* [Index](genindex.html)

* [Module Index](py-modindex.html)

* [Search Page](search.html)

