sh commands

XAL provides an interface to run shell commands through sh.

Tip

With a local session, XAL is a convenient subprocess wrapper.

Differences with subprocess

XAL’s sh interface is made to run sh commands in a session. Think of the commands always run with sh -c. Whereas Python’s subprocess sets shell=False by default.

This postulate influences design. XAL’s sh interface helps you create and run commands through sh: pipes, redirects...

“sh” provider in session’s registry

Let’s start with a local session:

>>> from xal.session.local import LocalSession
>>> session = LocalSession()

By default, in LocalSession, “sh” provider is xal.sh.local.LocalShProvider:

>>> session.registry.default('sh')  # Doctest: +ELLIPSIS
<xal.sh.local.LocalShProvider object at 0x...>

For convenience, we will set sh as a shortcut for session.sh:

>>> sh = session.sh

The ShCommand resource

The sh interface can be used as a factory to create xal.sh.resource.ShCommand resources:

>>> sh("echo -n 'Hello world!'")  # Doctest: +ELLIPSIS
<xal.sh.resource.ShCommand object at 0x...>

Command resources are not executed automatically once created. You have to run them explicitely. They are callables. When called, they return a xal.sh.resource.ShResult instance:

>>> command = sh("echo -n 'Hello world!'")
>>> result = command()
>>> result  # Doctest: +ELLIPSIS
<xal.sh.resource.ShResult object at 0x...>
>>> result.stdout
'Hello world!'
>>> result.return_code
0
>>> result.succeeded
True

Command constructor accepts strings or iterables:

>>> sh("echo -n 'Hello world!'")().stdout
'Hello world!'
>>> sh(["echo", "-n", "Hello world!"])().stdout
'Hello world!'

The sh interface has a run() shortcut that creates and runs Cmd instances:

>>> sh.run("echo -n 'Hello world!'").stdout
'Hello world!'
>>> sh.run(["echo", "-n", "Hello world!"]).stdout
'Hello world!'
>>> command = sh("echo -n 'Hello world!'")
>>> sh.run(command).stdout
'Hello world!'

You can create a resource for later use in one or several sessions:

>>> hello = sh("echo -n 'Hello world!'")
>>> from xal.session.local import LocalSession
>>> session = LocalSession()
>>> session.sh.run(hello).stdout
'Hello world!'

Pipes

You can create and handle pipes, they are commands too:

>>> echo = sh("echo -e 'hello\nworld'")
>>> grep = sh("grep 'world'")
>>> piped = echo.pipe(grep)
>>> piped().stdout
'world\n'
>>> piped = echo | grep
>>> piped().stdout
'world\n'
>>> sh.run(echo | grep).stdout
'world\n'