2010-07-17 6 views
1

Прежде всего позвольте мне сказать, что я знаю, что лучше использовать модуль подпроцесса, но я редактирую код других людей, и я стараюсь сделать как можно меньше изменений, что позволяет избежать импорта любых новых модулей. Поэтому я хотел бы придерживаться в настоящее время импортированных модулей (os, sys и paths), если это вообще возможно.Как использовать os.spawnv для отправки копии электронной почты с помощью Python?

Код в настоящее время (в файле с именем postfix-to-mailman.py, что некоторые из вас могут быть знакомы с):

if local in ('postmaster', 'abuse', 'mailer-daemon'): 
    os.execv("/usr/sbin/sendmail", ("/usr/sbin/sendmail", '[email protected]')) 
    sys.exit(0) 

Это прекрасно работает (хотя я думаю sys.exit (0) никогда не может быть вызвана и, следовательно, не нужна).

Я считаю, что это заменяет текущий процесс вызовом/usr/sbin/sendmail, передавая ему аргументы/usr/sbin/sendmail (для argv [0], т.е. самого себя) и '[email protected]', затем передает среду текущего процесса - включая сообщение электронной почты в sys.stdin - дочернему процессу.

Что бы я хотел сделать, это по существу отправить еще одну копию сообщения, прежде чем делать это. Я не могу использовать execv снова, потому что тогда выполнение остановится. Таким образом, я попытался следующее:

if local in ('postmaster', 'abuse', 'mailer-daemon'): 
    os.spawnv(os.P_WAIT, "/usr/sbin/sendmail", ("/usr/sbin/sendmail", '[email protected]')) 
    os.execv("/usr/sbin/sendmail", ("/usr/sbin/sendmail", '[email protected]')) 
    sys.exit(0) 

Однако, в то время как он посылает сообщение [email protected], он никогда не посылает его [email protected]

Это удивило меня, потому что я думал, что с помощью spawn начнет дочерний процесс, а затем продолжит выполнение в текущем процессе, когда он вернется (или не ждет, если используется P_NOWAIT).

Кстати, я сначала пробовал os.P_NOWAIT, но сообщение, которое я получил на другом@place.com, было пустым, поэтому, по крайней мере, когда я использовал P_WAIT, сообщение получилось неповрежденным. Но это все еще никогда не отправляется на [email protected], что является проблемой.

Я бы предпочел не использовать os.system, если я могу избежать этого, потому что я бы предпочел не выходить в среду оболочки, если ее можно избежать (проблемы безопасности, возможная производительность?) Я признаю, что я параноик здесь , но если я смогу избежать os.system, я бы все равно хотел).

Единственное, что я могу придумать, это то, что вызов os.spawnv каким-то образом поглощает/освобождает содержимое sys.stdin, но это тоже не имеет смысла. Идеи?

ответ

1

Хотя это может иметь смысл, что действительно кажется случае

import os 

os.spawnv(os.P_WAIT,"/usr/bin/wc", ("/usr/bin/wc",)) 
os.execv("/usr/bin/wc", ("/usr/bin/wc",)) 

$ cat j.py | python j.py 
     4  6  106 
     0  0  0 

В этом случае вы можете сделать что-то вроде этого

import os 
import sys 

buf = sys.stdin.read() 
wc = os.popen("usr/sbin/sendmail [email protected]","w") 
wc.write(buf) 
wc.close() 
wc = os.popen("usr/sbin/sendmail [email protected]","w") 
wc.write(buf) 
wc.close() 
sys.exit(0) 
+0

Hm, который может быть частью этого, но, к сожалению, вставка sys.stdin = sys .__ stdin__ между линиями spwnv и execv не работает, хотя http://docs.python.org/library/sys. html # sys.stdin говорит, что sys .__ stdin__ должен содержать исходное значение sys.stdin в начале программы. Blech. (но спасибо за тестирование этого и предоставление подсказки на пути к решению!) – Chirael

+0

Я думаю, что os.popen вызывает оболочку как os.system. Есть ли способ сделать то, что вы предлагаете, не выходя из командной оболочки? Я попытался сделать это с помощью popen2, 3, 4, но пока они принимают последовательности для аргументов и обходят оболочку, они не возвращают дескриптор файла, который можно записать (по-видимому). Благодаря! – Chirael

+0

Кстати, я чувствую, что главная проблема здесь в том, что итерация по sys.stdin - это разовый процесс; похоже, нет способа вернуться к началу sys.stdin для второго вызова: -/ – Chirael

0

sys.stdin представляет собой трубу, и тех, кто Арен 't seekable, чтобы вы никогда не могли перемотать этот файл-подобный объект, чтобы снова прочитать его содержимое. Чтобы на самом деле вызывать sendmail (1) дважды, вам нужно сохранить содержимое stdin, желательно во временном файле, но если данные гарантированно имеют ограниченный размер, вы можете сохранить его в памяти вместо этого.

Но зачем решать проблему? Вам конкретно нужна копия электронной почты для отправки по электронной почте отдельно (и если да, почему)? Просто добавьте желаемого получателя в исходный вызов sendmail (1). Дополнительный получатель не будет отображаться в заголовках электронной почты.

if local in ('postmaster', 'abuse', 'mailer-daemon'): 
    os.execv("/usr/sbin/sendmail", ("/usr/sbin/sendmail", 
            '[email protected]', 
            '[email protected]')) 
    sys.exit(0) 

О, и sys.exit (0) строка будет выполнена, если os.execv() по какой-то причине не удается.Это произойдет, если/usr/sbin/sendmail не могут быть выполнены, например. если исполняемый файл не существует или фактически не является исполняемым. Другими словами, это условие ошибки, о котором вам следует позаботиться.