get subprocess to format correctly - python

I am trying to execute an ansible-playbook commend in subprocess at the end of a python script, which does 'magic' before kicking off the correct command.
If you are not familiar with ansible-playbook. The output is normally colorful(green/yellow/red text) and is correctly spaced.
I would be fine if python just kicked off a command and exited if need be.
What I am getting currently is black and white text after the command has completed.
I want to get the normal color outout in real time as if I ran ansible-playbook from the command line. Is there a way to do this?
my current code is as follows:
command = '{0} --flush-cache -f 20 -i {1}/dyn_inv.py --extra-vars #{2}/vars.json {3}'.format(ansible_playbook_loc, script_path, var_path, args.playbook[0])
print command
process = subprocess.Popen(command.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
devices = process.communicate()[0].rstrip('\n').split()
print devices

Ansible by default will only colorize text when its output is connected to a terminal. You can force it to use color codes by setting ANSIBLE_FORCE_COLOR=1 in the environment. For example:
import os
os.environ['ANSIBLE_FORCE_COLOR'] = '1'
You can accomplish the same thing by setting the force_color option in your ansible.cfg.

Related

Executing bash command within a python script called from crontab

I am writing a python script, I want to call from crontab. It script calls the xrandr command and saves its output in a variable like so:
output = subprocess.run('xrandr', shell=True, stdout=subprocess.PIPE).stdout.decode('utf-8')
I want the output of xrandr to be saved in a string.
This works all fine if I execute it from terminal, but if I run it using cron, the variable output stays empty.
the rest of the code is executed normally, so cron isn't the problem.
So how can I make this command execute properly?
thank you for your suggestions.
You want to store output, you can use communicate() here to help out, so like this:
from subprocess import PIPE
output = subprocess.run('xrandr', shell=True, stdout=subprocess.PIPE).stdout.decode('utf-8')
text = output.communicate()[0]
print(text)
OR maybe this, in that case you can remove the .stdout.decode('utf-8') not too sure but it give a shot with and without it:
from subprocess import PIPE
output = subprocess.run('xrandr', shell=True, stdout=subprocess.PIPE).stdout.decode('utf-8')
print(output.stdout)
I guess in cron environment the PATH variable is not set, so you should provide absolute path to xrandr (you can find it by which xrandr).
E.g. if this path /usr/bin/xrandr try
from subprocess import PIPE
output = subprocess.run('/usr/bin/xrandr', shell=True, stdout=subprocess.PIPE).stdout.decode('utf-8')
text = output.communicate()[0]
print(text)
The better way for my opinion is to capture stderr as well and log error when it occures.

Start command prompt application/script from within Python, capture output and send input

I've been trying to run some applications with arguments in windows command prompt, but within a Python script. I am encountering issues in understanding the subprocess module and how I could use it to send inputs, capture outputs and use the data in future functions or loops.
Let's take, for example, Windows Management Instrumentation Command-Line:
I would like to launch a command prompt from a Python script, start wmic, do some stuff then exit back to command prompt.
I know how to strat the cmd and even wmic:
import subprocess
cmd = subprocess.Popen(["cmd", "/K", "wmic"])
What I don't know is how to send commands to wmic. I have tried the following:
import subprocess
cmd = subprocess.Popen(["cmd", "/K", "wmic"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdoutdata, stderrdata = cmd.communicate(input="product get name")
or
cmd.stdin.write("product get name")
cmd.stdin.flush()
Doesn't work. What I would've wanted in this example, is to start Command Prompt, start WMIC, send a command (product/process get name), capture the output of WMIC and use it to do something:
for line in cmd.stdout:
if line == "some string":
do this or do that
In the same time, I would like the output to be printed in the opened command prompt.
I would appreciate any help.

Loss of color when executing git through python

I have the following git extension script:
#!/usr/bin/env python
import sys
from subprocess import Popen, PIPE
if len(sys.argv) <= 1:
sys.argv = sys.argv + ['status']
git_cmd = 'git ' + ' '.join(sys.argv[1:])
print('--->', git_cmd)
#p = Popen(['git'] + sys.argv[1:], shell=True, stdout=PIPE)
p = Popen(git_cmd, shell=True, stdout=PIPE)
out, err = p.communicate()
print(out)
#print(str(out).encode('ascii'))
#print(out.decode('ascii'))
Basically I want to get the output of my Git command in a variable but I also want it to preserve the terminal color codes in the variable. So when I call print(out), it should print the colors too. Currently the string given back to me after calling communicate() does not have color information. If I remove stdout=PIPE from Popen(), then I do get colors, but the output goes directly to the output and I do not get it in a variable.
I'm running Python 3.4 rc2 on Windows through msysgit (not cmd.exe). So for example I will do this:
git index status --short
The command it runs is git status --short, the output contains no color information, but when I run the same command directly in msysgit terminal, it gives me colors.
Anyone know how I can get the color information back?
Set color.ui to always in your git configuration.
Note that this will break quite a lot of scripts (which, in general, don't expect color codes interspersed in content they're reading from git subcommands).
To update this temporarily, you can pass -c color.ui=always on the command line, or set the GIT_CONFIG environment variable to point to a config file with this setting only when your script is in operation.
Alternately, you can just stop using stdout=PIPE, output will be direct to the TTY instead of captured by your program (which is sensible, as your program is doing absolutely nothing with it other than printing), and git will colorize by default.

how can I silence all of the output from a particular python command?

Autodesk Maya 2012 provides "mayapy" - a modded build of python filled with the necessary packages to load Maya files and act as a headless 3D editor for batch work. I'm calling it from a bash script. If that script opens a scene file in it with cmds.file(filepath, open=True), it spews pages of warnings, errors, and other info I don't want. I want to turn all of that off only while the cmds.file command is running.
I've tried redirecting from inside of the Python commands I'm sending into mayapy inside the shell script, but that doesn't work. I can silence everything by redirecting stdout/err to /dev/null in the call to the bash script. Is there any way to silence it in the call to the shell, but still allow my passed-in command inside the script to print out information?
test.sh:
#!/bin/bash
/usr/autodesk/maya/bin/mayapy -c "
cmds.file('filepath', open=True);
print 'hello'
"
calling it:
$ ./test.sh # spews info, then prints 'hello'
$ ./test.sh > /dev/null 2>&1 # completely silent
Basically, I think the best way to solve this is to implement a wrapper that will execute test.sh and sanitize the output to the shell. To sanitize the output, I would simply prepend some string to notify your wrapper that this text is good for output. My inspiration for the wrapper file came from this: https://stackoverflow.com/a/4760274/2030274
The contents are as follows:
import subprocess
def runProcess(exe):
p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while(True):
retcode = p.poll() #returns None while subprocess is running
line = p.stdout.readline()
yield line
if(retcode is not None):
break
for line in runProcess(['./test.sh']):
if line.startswith('GARYFIXLER:'):
print line,
Now you could imagine test.sh being something along the lines of
#!/bin/bash
/usr/autodesk/maya/bin/mayapy -c "
cmds.file('filepath', open=True);
print 'GARYFIXLER:hello'
"
and this will only print the hello line. Since we are wrapping the python call in a subprocess, all output typically displayed to the shell should get captured and you should intercept the lines that you don't want.
Of course, to call test.sh from a python script, you need to make sure you have the correct permissions.
I knew I was just getting twisted around with pipes. Maya is indeed sending all batch output to stderror. This frees stdout entirely once you properly pipe stderr away. Here's an all-bash one-liner that works.
# load file in batch; divert Maya's output to /dev/null
# then print listing of things in file with cmds.ls()
/usr/autodesk/maya/bin/mayapy -c "import maya.standalone;maya.standalone.initialize(name='python');cmds.file('mayafile.ma', open=True);print cmds.ls()" 2>/dev/null

How to execute a command prompt command from python

I tried something like this, but with no effect:
command = "cmd.exe"
proc = subprocess.Popen(command, stdin = subprocess.PIPE, stdout = subprocess.PIPE)
proc.stdin.write("dir c:\\")
how about simply:
import os
os.system('dir c:\\')
You probably want to try something like this:
command = "cmd.exe /C dir C:\\"
I don't think you can pipe into cmd.exe... If you are coming from a unix background, well, cmd.exe has some ugly warts!
EDIT: According to Sven Marnach, you can pipe to cmd.exe. I tried following in a python shell:
>>> import subprocess
>>> proc = subprocess.Popen('cmd.exe', stdin = subprocess.PIPE, stdout = subprocess.PIPE)
>>> stdout, stderr = proc.communicate('dir c:\\')
>>> stdout
'Microsoft Windows [Version 6.1.7600]\r\nCopyright (c) 2009 Microsoft Corporatio
n. All rights reserved.\r\n\r\nC:\\Python25>More? '
As you can see, you still have a bit of work to do (only the first line is returned), but you might be able to get this to work...
Try:
import os
os.popen("Your command here")
Using ' and " at the same time works great for me (Windows 10, python 3)
import os
os.system('"some cmd command here"')
for example to open my web browser I can use this:
os.system(r'"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"')
(Edit)
for an easier way to open your browser I can use this:
import webbrowser
webbrowser.open('website or leave it alone if you only want to open the
browser')
Try adding a call to proc.stdin.flush() after writing to the pipe and see if things start behaving more as you expect. Explicitly flushing the pipe means you don't need to worry about exactly how the buffering is set up.
Also, don't forget to include a "\n" at the end of your command or your child shell will sit there at the prompt waiting for completion of the command entry.
I wrote about using Popen to manipulate an external shell instance in more detail at: Running three commands in the same process with Python
As was the case in that question, this trick can be valuable if you need to maintain shell state across multiple out-of-process invocations on a Windows machine.
Taking some inspiration from Daren Thomas's answer (and edit), try this:
proc = subprocess.Popen('dir C:\\', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
out, err = proc.communicate()
out will now contain the text output.
They key nugget here is that the subprocess module already provides you shell integration with shell=True, so you don't need to call cmd.exe directly.
As a reminder, if you're in Python 3, this is going to be bytes, so you may want to do out.decode() to convert to a string.
Why do you want to call cmd.exe ? cmd.exe is a command line (shell). If you want to change directory, use os.chdir("C:\\"). Try not to call external commands if Python can provide it. In fact, most operating system commands are provide through the os module (and sys). I suggest you take a look at os module documentation to see the various methods available.
It's very simple. You need just two lines of code with just using the built-in function and also it takes the input and runs forever until you stop it. Also that 'cmd' in quotes, leave it and don't change it. Here is the code:
import os
os.system('cmd')
Now just run this code and see the whole windows command prompt in your python project!
Here's a way to just execute a command line command and get its output using the subprocess module:
import subprocess
# You can put the parts of your command in the list below or just use a string directly.
command_to_execute = ["echo", "Test"]
run = subprocess.run(command_to_execute, capture_output=True)
print(run.stdout) # the output "Test"
print(run.stderr) # the error part of the output
Just don't forget the capture_output=True argument and you're fine. Also, you will get the output as a binary string (b"something" in Python), but you can easily convert it using run.stdout.decode().
In Python, you can use CMD commands using these lines :
import os
os.system("YOUR_COMMAND_HERE")
Just replace YOUR_COMMAND_HERE with the command you like.
From Python you can do directly using below code
import subprocess
proc = subprocess.check_output('C:\Windows\System32\cmd.exe /k %windir%\System32\\reg.exe ADD HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /t REG_DWORD /d 0 /f' ,stderr=subprocess.STDOUT,shell=True)
print(str(proc))
in first parameter just executed User Account setting you may customize with yours.

Categories

Resources