How do I call an external command within Python as if I had typed it in a shell or command prompt?
66 Answers
I have written a wrapper to handle errors and redirecting output and other stuff.
import shlex
import psutil
import subprocess
def call_cmd(cmd, stdout=sys.stdout, quiet=False, shell=False, raise_exceptions=True, use_shlex=True, timeout=None):
"""Exec command by command line like 'ln -ls "/var/log"'
"""
if not quiet:
print("Run %s", str(cmd))
if use_shlex and isinstance(cmd, (str, unicode)):
cmd = shlex.split(cmd)
if timeout is None:
process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, shell=shell)
retcode = process.wait()
else:
process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, shell=shell)
p = psutil.Process(process.pid)
finish, alive = psutil.wait_procs([p], timeout)
if len(alive) > 0:
ps = p.children()
ps.insert(0, p)
print('waiting for timeout again due to child process check')
finish, alive = psutil.wait_procs(ps, 0)
if len(alive) > 0:
print('process {} will be killed'.format([p.pid for p in alive]))
for p in alive:
p.kill()
if raise_exceptions:
print('External program timeout at {} {}'.format(timeout, cmd))
raise CalledProcessTimeout(1, cmd)
retcode = process.wait()
if retcode and raise_exceptions:
print("External program failed %s", str(cmd))
raise subprocess.CalledProcessError(retcode, cmd)
You can call it like this:
cmd = 'ln -ls "/var/log"'
stdout = 'out.txt'
call_cmd(cmd, stdout)
Comments
Python 3.5+
import subprocess
p = subprocess.run(["ls", "-ltr"], capture_output=True)
print(p.stdout.decode(), p.stderr.decode())
Comments
Using the Python subprocess module to execute shell commands and write the output to a file.
The below script will run the ps -ef command, filter lines containing python3, and write them to a file called python_processes.txt. Note that the code does not handle any exceptions that might occur during execution.
import subprocess
# Command to execute
cmd = ["ps", "-ef"]
# Execute the command
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
output, error = process.communicate()
# Check if the command was executed without errors
if error is None:
# Filter lines with 'python3'
python_processes = [line for line in output.decode('utf-8').split('\n') if 'python3' in line]
# Write the output to a file
with open('python_processes.txt', 'w') as f:
for process in python_processes:
f.write(process + '\n')
else:
print(f"Error occurred while executing command: {error}")
Comments
Sultan is a recent-ish package meant for this purpose. It provides some niceties around managing user privileges and adding helpful error messages.
from sultan.api import Sultan
with Sultan.load(sudo=True, hostname="myserver.com") as sultan:
sultan.yum("install -y tree").run()
Comments
Here is a Python script that will run the command on Ubuntu, while also showing the logs in real-time:
command = 'your command here'
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while True:
output = process.stdout.readline().decode()
if output == '' and process.poll() is not None:
break
if output:
print(output.strip())
rc = process.poll()
if rc == 0:
print("Command succeeded.")
else:
print("Command failed.")
Comments
I use this for Python 3.6+:
import subprocess
def execute(cmd):
"""
Purpose : To execute a command and return exit status
Argument : cmd - command to execute
Return : result, exit_code
"""
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(result, error) = process.communicate()
rc = process.wait()
if rc != 0:
print ("Error: failed to execute command: ", cmd)
print (error.rstrip().decode("utf-8"))
return result.rstrip().decode("utf-8"), serror.rstrip().decode("utf-8")
# def
1 Comment
shell=True to run commands, it opens the program to command injection vulnerabilities. You're supposed to pass the command as a list with arguments cmd=["/bin/echo", "hello word"]. docs.python.org/3/library/…