I am writting a Python script and I am running out of time. I need to do some things that I know pretty well in bash, so I just wonder how can I embed some bash lines into a
Is
import os
os.system ("bash -c 'echo $0'")
going to do it for you?
EDIT: regarding readability
Yes, of course, you can have it more readable
import os
script = """
echo $0
ls -l
echo done
"""
os.system("bash -c '%s'" % script)
EDIT2: regarding macros, no python does not go so far as far as i know, but between
import os
def sh(script):
os.system("bash -c '%s'" % script)
sh("echo $0")
sh("ls -l")
sh("echo done")
and previous example, you basically get what you want (but you have to allow for a bit of dialectical limitations)
If you want to call system commands, use the subprocess module.
The ideal way to do it:
def run_script(script, stdin=None):
"""Returns (stdout, stderr), raises error on non-zero return code"""
import subprocess
# Note: by using a list here (['bash', ...]) you avoid quoting issues, as the
# arguments are passed in exactly this order (spaces, quotes, and newlines won't
# cause problems):
proc = subprocess.Popen(['bash', '-c', script],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
stdin=subprocess.PIPE)
stdout, stderr = proc.communicate()
if proc.returncode:
raise ScriptException(proc.returncode, stdout, stderr, script)
return stdout, stderr
class ScriptException(Exception):
def __init__(self, returncode, stdout, stderr, script):
self.returncode = returncode
self.stdout = stdout
self.stderr = stderr
Exception.__init__('Error in script')
You might also add a nice __str__
method to ScriptException
(you are sure to need it to debug your scripts) -- but I leave that to the reader.
If you don't use stdout=subprocess.PIPE
etc then the script will be attached directly to the console. This is really handy if you have, for instance, a password prompt from ssh. So you might want to add flags to control whether you want to capture stdout, stderr, and stdin.
Assuming the command is supported by the host system:
import os
os.system('command')
If you have a long command, or a set of commands. you can use variables. eg:
# this simple line will capture column five of file.log
# and then removed blanklines, and gives output in filtered_content.txt.
import os
filter = "cat file.log | awk '{print $5}'| sed '/^$/d' > filtered_content.txt"
os.system(filter)
As aforementioned, you could use os.system(); it's quick and dirty, bu it's easy to use and works for most cases. It's literally a mapping on to the C system() function.
http://docs.python.org/2/library/os.html#os.system
http://www.cplusplus.com/reference/cstdlib/system/
@Ian Bicking
's answer is useful but it if only allow us to run scripts. Instead we can come up with a more flexible code where we can run command as well. I have a different approach from his.
#!/usr/bin/env python3
from subprocess import Popen, PIPE
class BashCommandsException(Exception):
def __init__(self, returncode, output, error_msg):
self.returncode = returncode
self.output = output
self.error_msg = error_msg
Exception.__init__('Error in executed command')
def popen_communicate(cmd, stdout_file=None):
"""Acts similir to lib.run(cmd) but also returns the output message captures on
during the run stdout_file is not None in case of nohup process writes its
results into a file
"""
cmd = list(map(str, cmd)) # all items should be string
if stdout_file is None:
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
else:
with open(stdout_file, "w") as outfile:
# output written into file, error will be returned
p = Popen(cmd, stdout=outfile, stderr=PIPE, universal_newlines=True)
output, error = p.communicate()
p.wait()
return p, output, error
output, error = p.communicate()
output = output.strip().decode("utf-8")
error = error.decode("utf-8")
return p, output, error
def run(cmd):
log_file = "/tmp/log.txt"
# if log_file is not provided returned output will be stored in output
p, output, error_msg = popen_communicate(cmd, log_file)
if p.returncode != 0:
raise BashCommandsException(p.returncode, output, error_msg, str(cmd))
return output
if __name__ == "__main__":
# This could be any command you want to execute as you were in bash
cmd = ["bash", "script_to_run.sh"]
try:
run(cmd)
except Exception as e:
print(e)