Executing commands in a subprocess¶
MILC provides some tools to make running subcommands easier and more convienent to work with.
Basic Subprocess Execution¶
You can use
cli.run() to easily and safely run shell commands. The first argument to
cli.run() should be an argument list, which is a list or tuple containing the command and any arguments you want to pass in. For example, if you wanted to run a git command you might build this argument list:
git_cmd = ['git', '-C', '/srv/web/htdocs', 'pull']
This is all you need to do to run that command:
p = cli.run(git_cmd)
This will return a subprocess.CompletedProcess instance. You can examine attributes such as
p.stdout to see the fate of the process.
||A sequence of arguments for the command to be run. The first element is the command to be executed.|
||Any unrecognized argument will be passed to
Differences from subprocess.run¶
cli.run() differs from
subprocess.run() in some important ways.
When running inside a windows console (Powershell, DOS, Cygwin, Msys2) there are some quirks that MILC attempts to handle but which you need to be aware of:
- Commands are always run in a subshell, so that non-executable files and POSIX paths work seemlessly.
- Windows leaves stdin in a broken state after executing a subprocess. To avoid this MILC adds
subprocess.run()call. If you need stdin to work in your executed process you can pass
Building argument lists¶
The most important way MILC differs from
subprocess.run() is that it only accepts commands that have already been split into sequences. A lot of bugs are caused by mistakes in building command strings that are later split into a sequence of arguments in unexpected ways.
cli.run() captures STDOUT and STDERR. If you'd like that output to be written to the terminal instead you can pass
Combining STDERR with STDOUT¶
If you'd like to combine STDOUT and STDERR into one stream (similar to the shell construct
2>&1) you can pass
By default STDOUT and STDERR will be opened as text. If you'd like these to be bytes instead of text you can pass
All other arguments are passed directly to
subprocess.run(). You can use these to further tweak the behavior of your subprocesses.