Hello again, I've finally found some time to partially process the replies and came up with a better solution than subprocess.* and shutil.runret/runout Disclaimer: I don't say that suprocess suxx - it is powerful and very awesome under the hood. What I want to say that its final user interface is awful - for such complex thing as this it should have been passed through several iteration cycles before settling down. Therefore, inspired by Fabric API, I've finally found the solution - shutil.run() function: https://bitbucket.org/techtonik/shutil-run/src run(command, combine_stderr=True): Run command through a system shell, return output string with additional properties: output.succeeded - result of the operation True/False output.return_code - specific return code output.stderr - stderr contents if combine_stderr=False `combine_stderr` if set, makes stderr merged into output string, otherwise it will be available as `output.stderr` attribute. Example: from shellrun import run output = run('ls -la') if output.succeeded: print(output) else: print("Error %s" % output.return_code) That's the most intuitive way I found so far. Objective advantages: 1. Better than subprocess.call(cmd, shell=true) subprocess.check_call(cmd, shell=true) subprocess.check_output(cmd, shell=True) because it is just shutil.run(cmd) i.e. short, simple and _easy to remember_ 2. With shutil.run() you don't need to rewrite your check_call() or check_output() with Popen() if you need to get return_code in addition to stderr contents on error 3. shutil.run() is predictable and consistent - its arguments are not dependent on each other, their combination doesn't change the function behavior over and over requiring you iterate over the documentation and warnings again and again 4. shutil.run() is the correct next level API over subprocess base level. subprocess executes external process - that is its role, but automatic ability to execute external process inside another external process (shell) looks like a hack to me. Practical, but still a hack. 5. No required exception catching, which doesn't work for shell=True anyway 6. No need to learn subprocess.PIPE routing magic (not an argument for hackers, I know) Subjective advantages: 1. More beautiful 2. More simple 3. More readable 4. Practical 5. Obvious 6. It easy to explain Hopefully, it can find its way in stdlib instead of http://shell-command.readthedocs.org/ -- anatoly t.