आप subprocess
के साथ ऐसा कर सकते हैं, लेकिन यह मामूली नहीं है। यदि आप दस्तावेज़ों में Frequently Used Arguments देखते हैं, तो आप देखेंगे कि आप PIPE
को stderr
तर्क के रूप में पास कर सकते हैं, जो एक नई पाइप बनाता है, पाइप के एक तरफ बच्चे की प्रक्रिया में गुजरता है, और दूसरी तरफ उपयोग करने के लिए उपलब्ध कराता है stderr
विशेषता। *
तो, आपको उस पाइप की सेवा करने की आवश्यकता होगी, स्क्रीन पर और फ़ाइल में लिखना होगा। आम तौर पर, इसके लिए विवरण प्राप्त करना बहुत मुश्किल है। ** आपके मामले में, केवल एक पाइप है, और आप इसे समकालिक रूप से सर्विस करने की योजना बना रहे हैं, इसलिए यह बुरा नहीं है।
import subprocess
proc = subprocess.Popen(['path_to_tool', '-option1', 'option2'],
stdout=file_out, stderr=subprocess.PIPE)
for line in proc.stderr:
sys.stdout.write(line)
log_file.write(line)
proc.wait()
(ध्यान दें कि कुछ for line in proc.stderr:
उपयोग करने में समस्याएं -basically हैं कि, क्या आप पढ़ रहे हैं पता चला है कि अगर किसी भी कारण से लाइन बफ़र नहीं होने के लिए आपको एक नई पंक्ति के लिए इंतज़ार कर चारों ओर बैठ सकते हैं वहाँ वास्तव में आधा है, भले ही प्रक्रिया के लिए डेटा की एक लाइन मूल्य। यदि आवश्यक हो तो डेटा को अधिक सुचारु रूप से प्राप्त करने के लिए, read(128)
, या यहां तक कि read(1)
के साथ, आप एक बार में भाग पढ़ सकते हैं। यदि आपको वास्तव में आने वाले हर बाइट को वास्तव में प्राप्त करने की आवश्यकता होती है, और कर सकते हैं read(1)
की लागत का खर्च नहीं उठाएगा, आपको पाइप को गैर-अवरुद्ध मोड में डालना होगा और अतुल्यकालिक रूप से पढ़ना होगा।)
लेकिन यदि आप यूनिक्स पर हैं, तो tee
कमांड का उपयोग करने के लिए यह आसान हो सकता है।
त्वरित & गंदे समाधान के लिए, आप खोल के माध्यम से पाइप का उपयोग कर सकते हैं। इस तरह कुछ:
subprocess.call('path_to_tool -option1 option2 2|tee log_file 1>2', shell=True,
stdout=file_out)
लेकिन मैं खोल पाइपिंग डीबग नहीं करना चाहता; यह अजगर में करते हैं, जैसा कि दिखाया गया in the docs करते हैं:
tool = subprocess.Popen(['path_to_tool', '-option1', 'option2'],
stdout=file_out, stderr=subprocess.PIPE)
tee = subprocess.Popen(['tee', 'log_file'], stdin=tool.stderr)
tool.stderr.close()
tee.communicate()
अंत में, एक दर्जन या अधिक subprocesses और/या PyPI- sh
, shell
, shell_command
, shellout
पर खोल के आसपास उच्च स्तर के रैपर, iterpipes
, sarge
, cmd_utils
, commandwrapper
, आदि "खोल", "सबप्रोसेस", "प्रक्रिया", "कमांड लाइन" आदि के लिए खोजें और अपनी पसंद के किसी को ढूंढें जो समस्या को तुच्छ बनाता है।
क्या होगा यदि आपको दोनों stderr और stdout को इकट्ठा करने की आवश्यकता है?
ऐसा करने का आसान तरीका सिर्फ एक को दूसरे पर रीडायरेक्ट करना है, क्योंकि स्वेन मार्नैच ने एक टिप्पणी में सुझाव दिया है। बस इस तरह Popen
पैरामीटर बदल:।
tool = subprocess.Popen(['path_to_tool', '-option1', 'option2'],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
और फिर हर जगह आप tool.stderr
इस्तेमाल किया, tool.stdout
बजाय-उदाहरण के लिए: उपयोग करते हैं, पिछले उदाहरण के लिए:
tee = subprocess.Popen(['tee', 'log_file'], stdin=tool.stdout)
tool.stdout.close()
tee.communicate()
लेकिन यह कुछ समझौतों से है। सबसे स्पष्ट रूप से, दो धाराओं को एक साथ मिलाकर इसका मतलब है कि आप log_file पर file_out और stderr पर stdout लॉग नहीं कर सकते हैं, या अपने stdout और stderr पर stdout को अपने stderr पर कॉपी कर सकते हैं। लेकिन इसका मतलब यह भी है कि ऑर्डरिंग गैर-निर्धारिती हो सकती है- यदि सबप्रोसेस स्टडआउट पर कुछ भी लिखने से पहले हमेशा दो पंक्तियों को लिखता है, तो आप धाराओं को मिश्रण करने के बाद उन दो लाइनों के बीच स्टडआउट का गुच्छा प्राप्त कर सकते हैं। और इसका मतलब है कि उन्हें स्टडआउट के बफरिंग मोड को साझा करना होगा, इसलिए यदि आप इस तथ्य पर भरोसा कर रहे हैं कि लिनक्स/ग्लिबैक लाइनर-बफर किए जाने के लिए stderr की गारंटी देता है (जब तक उपप्रोसेस स्पष्ट रूप से इसे परिवर्तित नहीं करता), जो अब सत्य नहीं हो सकता है।
यदि आपको दो प्रक्रियाओं को अलग से संभालने की आवश्यकता है, तो यह अधिक कठिन हो जाता है। इससे पहले, मैंने कहा था कि फ्लाई पर पाइप की सेवा करना तब तक आसान है जब तक आपके पास केवल एक पाइप हो और इसे समकालिक रूप से सेवा दे सके। यदि आपके पास दो पाइप हैं, तो यह स्पष्ट रूप से अब सत्य नहीं है। कल्पना करें कि आप tool.stdout.read()
पर प्रतीक्षा कर रहे हैं, और नया डेटा tool.stderr
से आता है। यदि बहुत अधिक डेटा है, तो यह पाइप को ओवरफ्लो और उपप्रोसेस को अवरुद्ध कर सकता है। लेकिन अगर ऐसा नहीं होता है, तो आप स्पष्ट रूप से stdr डेटा को पढ़ने और लॉग इन करने में सक्षम नहीं होंगे जब तक कि stdout से कुछ नहीं आता है।
यदि आप पाइप-थ्रू -tee
समाधान का उपयोग करते हैं, जो प्रारंभिक समस्या से बचाता है ... लेकिन केवल एक नई परियोजना बनाकर जो खराब है। आपके पास दो tee
उदाहरण हैं, और जब आप एक पर communicate
पर कॉल कर रहे हैं, तो दूसरा हमेशा के लिए प्रतीक्षा कर रहा है।
तो, किसी भी तरह से, आपको किसी प्रकार की असीमित तंत्र की आवश्यकता है। आप यह थ्रेड के साथ कर सकते हैं, select
रिएक्टर, gevent
आदि जैसे कुछ।
proc = subprocess.Popen(['path_to_tool', '-option1', 'option2'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def tee_pipe(pipe, f1, f2):
for line in pipe:
f1.write(line)
f2.write(line)
t1 = threading.Thread(target=tee_pipe, args=(proc.stdout, file_out, sys.stdout))
t2 = threading.Thread(target=tee_pipe, args=(proc.stderr, log_file, sys.stderr))
t3 = threading.Thread(proc.wait)
t1.start(); t2.start(); t3.start()
t1.join(); t2.join(); t3.join()
हालांकि, कुछ मामलों में जहां बढ़त है कि काम नहीं करेगा कर रहे हैं:
यहां एक त्वरित और गंदे उदाहरण है। (समस्या वह क्रम है जिसमें सिग्चाल्ड और सिगिपिप/ईपीआईपीई/ईओएफ आते हैं। मुझे नहीं लगता कि इनमें से कोई भी हमें प्रभावित करेगा, क्योंकि हम कोई इनपुट नहीं भेज रहे हैं ... लेकिन मुझे इस पर भरोसा न करें के माध्यम से और/या परीक्षण।) 3.3+ से subprocess.communicate
फ़ंक्शन सभी स्पष्ट विवरण सही हो जाता है। लेकिन आपको एपीआईएनसी-सबप्रोसेस रैपर कार्यान्वयन में से एक का उपयोग करना बहुत आसान हो सकता है जो आप पीपीपीआई और एक्टिवस्टेट पर पा सकते हैं, या यहां तक कि उप-प्रोसेस सामग्री जैसे ट्विस्टेड जैसे पूर्ण एसिंक फ्रेमवर्क से भी मिल सकते हैं।
* डॉक्स वास्तव में व्याख्या नहीं करते क्या पाइप कर रहे हैं, लगभग रूप में यदि वे आप एक पुराने यूनिक्स सी हाथ होने की उम्मीद ... लेकिन कुछ उदाहरण, विशेष रूप से Replacing Older Functions with the subprocess
Module अनुभाग में, दिखाने के वे कैसे कर रहे हैं इस्तेमाल किया, और यह बहुत आसान है।
** कठिन हिस्सा दो या दो से अधिक पाइप ठीक से अनुक्रमित कर रहा है। यदि आप एक पाइप पर इंतजार करते हैं, तो दूसरा ओवरफ्लो और अवरुद्ध हो सकता है, जिससे आप किसी अन्य को कभी खत्म होने से रोक सकते हैं। इसके चारों ओर जाने का एकमात्र आसान तरीका प्रत्येक पाइप की सेवा के लिए धागा बनाना है। (अधिकांश * निक्स प्लेटफार्मों पर, आप select
या poll
रिएक्टर का उपयोग कर सकते हैं, लेकिन यह क्रॉस-प्लेटफ़ॉर्म आश्चर्यजनक रूप से कठिन है।) The source मॉड्यूल में, विशेष रूप से communicate
और इसके सहायक, यह दिखाता है कि यह कैसे करें। (मैं 3.3 से जुड़ा हुआ हूं, क्योंकि पिछले संस्करणों में, communicate
स्वयं कुछ महत्वपूर्ण चीजें गलत हो जाता है ...) यही कारण है कि, जब भी संभव हो, आप communicate
का उपयोग करना चाहते हैं यदि आपको एक से अधिक पाइप की आवश्यकता है। आपके मामले में, आप communicate
का उपयोग नहीं कर सकते हैं, लेकिन सौभाग्य से आपको एक से अधिक पाइप की आवश्यकता नहीं है।
अपने कोड विंडोज (या अन्य गैर POSIXy प्लेटफार्मों) पर काम करने की जरूरत है? यदि नहीं, तो एक आसान जवाब है। – abarnert
इसकी आवश्यकता नहीं है! –
संबंधित: [पायथन उपप्रोसेज को बच्चों के आउटपुट को फ़ाइल और टर्मिनल में मिलता है?] (Http://stackoverflow.com/q/4984428/4279) – jfs