Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python subprocess: why won't the list of arguments work analogous to the full shell string?

Thanks in advance for any help. I am new to python, but not particularly new to scripting. I am trying to run a simple, automated email program, but the email module seems to be installed incorrectly on our system (I don't have 75% of the functions described in the python examples, only "message_from_string" and "message_from_file") and smtplib is overly complicated for what I need.

In fact, in simple bash terms, all I need is:

/bin/email -s "blah" "recipients" < file.with.body.info.txt

or,

echo "my body details" | /bin/email -s "blah" "recipients"

so that I can avoid having to write to a file just to send a message.

I tried using subprocess, either call or Popen, and the only way I could eventually get things to work is if I used:

subprocess.call('/bin/mail -s "blah" "recipients" < file.with.body.info.txt', shell=True)

A few things I specifically don't like about this method:

(1) I couldn't break things into a list or tuple, as it is supposed to work, so that I lost the whole advantage of subprocess, as I understand it, in keeping things secure. If I tried:

subprocess.call(['/bin/mail', '-s', subjVariable, recipVariable, '<', 'file.with.body.info.txt'], shell=True)

it would fail. Similarly, if I tried to use the pipe, '|', instead of reading from a file, it would fail. It was also failing if I used '-cmd' instead of a pipe. The "fail" was usually that it would read '<' and 'file.with.body.info.txt' as if they were further recipients. In other words, whether I said "shell = True" or not, subprocess was not able to interpret the special characters in the call as the special characters that they are. '<' wasn't recognized as an input from a file, etc., unless I kept everything in one large call.

What I would ideally like to be able to do, because it seems more secure, as well as more flexible, is something like this:

subprocess.call(['/bin/echo', varWithBody, '|', '/bin/mail', '-s', subjVariable, recipVariable,])

but it seems that pipes are not understood at all with subprocess and I cannot figure out how to pipe things together while stuck behind python.

Any suggestions? All help is welcome, except attempts to explain how to use the 'email' or 'smtplib' modules. Regardless of this particular application, I really want to learn how to use subprocess better, so that I can tie together disparate programs. My understanding is that python should be fairly decent at that.

Thanks! Mike

like image 549
Mike Williamson Avatar asked Dec 06 '22 00:12

Mike Williamson


2 Answers

The Python docs seem to cover this situation.

What I'd probably do is something like the following

from subprocess import *
readBody = Popen(["/bin/echo", varWithBody], stdout=PIPE)
mail = Popen(["/bin/mail", "-s", subjVariable, recipVariable], stdin=readBody.stdout, stdout=PIPE)
output = mail.communicate()[0]
like image 184
Steve V. Avatar answered Dec 10 '22 10:12

Steve V.


| and < are not arguments; they are shell redirections. To replace the | in your code, see these instructions.

To replace <, use:

 subprocess.Popen(["command", "args"], stdin=open("file.txt", 'r'))

eg.

subprocess.Popen(["cat"], stdin=open("file.txt", 'r')) is the same as cat < file.txt

like image 35
david4dev Avatar answered Dec 10 '22 10:12

david4dev