Run An External Command From A Python Script

January - 2022

TODO: Update this to process the output directly instead of looking at stdout by itself

#!/usr/bin/env python3

import subprocess


results = subprocess.run(
	['ls', '-l'], 
	capture_output=True,
	check=True
)

stdout = results.stdout.decode('utf-8')
stderr = results.stderr.decode('utf-8')

print(stdout)

print(stderr)

For those times when you need to execute another process

import subprocess

response = subprocess.run(['ls', '-la'], stdout=subprocess.PIPE).stdout.decode('utf-8')

It pulls the output from STDOUT into the variable.

There's another way to do this where you don't do the pipe and then pull the values from inside the response variable that is what you should probably move to since it gives you stderr as well


Note from the docs - The recommended approach to invoking subprocesses is to use the run() function for all use cases it can handle. For more advanced use cases, the underlying Popen interface can be used directly.

NOTE: subprocess.run does not work out of the box with pyfakefs

post- write these up with examples of all the different ways to get stuff with STDERR and STDOUT

via: https://stackoverflow.com/questions/89228/how-to-call-an-external-command

2020: Most Basic for after Python 3.5

    #!/usr/bin/env python3
    
    # This runs, but doesn't send results back to python, 
    import subprocess
    subprocess.run(["ls", "-l"])
    
    # If you do this:
    print(subprocess.run(["ls", "-l"]))
    
    # You get something like:
    # -rw-r--r--  1 alans  staff  187 Oct 20 20:46 test_credentials.py
    # CompletedProcess(args=['ls', '-l'], returncode=0)
    
    # But the line with the list stuff is directly from the
    # STDOUT that subprocess did. It's not what was passed 
    # back to print. 
    #Prior to Python 3.5

    #!/usr/bin/env python2
    

    import subprocess
    subprocess.call(["ls", "-l"])


TODO determine differ with stdout here


    subprocess.run().stdout.decode('utf-8')


Get just stdout with, see this below

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

# This one is how you run commands that are already assembled 

import os

os.system("some_command < input_file | another_command > output_file")


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




To pull the STDOUT directly (without access to STDERR) in a way that will just capture STDOUT , use

  # This is for python3
  
	import subprocess
	response = subprocess.run(['ls', '-la'], stdout=subprocess.PIPE).stdout.decode('utf-8')
	

> You can capture errors by passing stderr=subprocess.PIPE (capture to result.stderr) or stderr=subprocess.STDOUT (capture to result.stdout along with regular output). When security is not a concern, you can also run more complex shell commands by passing shell=True as described in the notes below.


via: [this StackOverflow Answer](https://stackoverflow.com/a/4760517/102401):
	

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


From [this StackOverflow Answer]	(https://stackoverflow.com/a/89243/102401):

> The advantage of subprocess vs. system is that it is more flexible (you can get the stdout, stderr, the "real" status code, better error handling, etc...).
> 
> The [official documentation](https://docs.python.org/3/library/os.html#os.system) recommends the subprocess module over the alternative os.system()


subprocess.check_output()
-------------------------

via: https://stackoverflow.com/a/4760517/102401

If you just need the output, use `subprocess.check_output`, like:

	response = subprocess.check_output(['awslocal', 'logs', 'describe-log-groups']).decode('utf-8')
	
The principal output is a binary object which is why the `.decode('utf-8')` is there

Apparently, this isn't the recommended approach, but it still works. 



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

This is how you can get output from an external command in python.

	import subprocess

	print subprocess.Popen("echo Hello World", stdout=subprocess.PIPE, shell=True).stdout.read()


Note that if you want to catch errors as well (for example to deal with git) it looks like you need to do something like:

	git_status_response = subprocess.Popen("git status", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True).stdout.read()
	

If you want to remove the newline from the end, you can add '.rstrip()'. for example:

	git_status_response = subprocess.Popen("git status", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True).stdout.read().rstrip()

That one is not tested yet, but another version like it worked.


Note, it looks like 'subprocess.check_output' doesn't always work. You had problems using it inside of Sublime Text.



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




---

Older Notes

This is from this [stack overflow question][1]


	def gitAdd(fileName, repoDir):
		cmd = ['git', 'add', fileName]
		p = subprocess.Popen(cmd, cwd=repoDir)
		p.wait()
	
	gitAdd('exampleFile.txt', '/usr/local/example_git_repo_dir')
	
	
[1]: http://stackoverflow.com/questions/1456269/python-git-module-experiences