2008-10-02 15 views
221

अगर मैं निम्न कार्य करें:पायथन - मैं subprocess.Popen (stdin तर्क का उपयोग कर) में एक स्ट्रिंग कैसे पास करूं?

import subprocess 
from cStringIO import StringIO 
subprocess.Popen(['grep','f'],stdout=subprocess.PIPE,stdin=StringIO('one\ntwo\nthree\nfour\nfive\nsix\n')).communicate()[0] 

मैं:

Traceback (most recent call last): 
    File "<stdin>", line 1, in ? 
    File "/build/toolchain/mac32/python-2.4.3/lib/python2.4/subprocess.py", line 533, in __init__ 
    (p2cread, p2cwrite, 
    File "/build/toolchain/mac32/python-2.4.3/lib/python2.4/subprocess.py", line 830, in _get_handles 
    p2cread = stdin.fileno() 
AttributeError: 'cStringIO.StringI' object has no attribute 'fileno' 

जाहिर है एक cStringIO.StringIO वस्तु एक फ़ाइल बतख के काफ़ी करीब subprocess.Popen सूट करने के लिए नीम हकीम नहीं है। मैं इसके आसपास कैसे काम करूं?

>>> p = subprocess.Popen(['grep','f'],stdout=subprocess.PIPE,stdin=subprocess.PIPE) 
>>> p.stdin.write(b'one\ntwo\nthree\nfour\nfive\nsix\n') #expects a bytes type object 
>>> p.communicate()[0] 
'four\nfive\n' 
>>> p.stdin.close() 

वहाँ एक बेहतर एक है:

+3

के बजाय इस हटाया जा रहा है, मैं इसे एक टिप्पणी ... अनुशंसित पढ़ने के रूप में जोड़ रहा साथ मेरा उत्तर विवाद: [डौग है Hellmann अजगर सबप्रोसेस पर सप्ताह ब्लॉग पोस्ट का मॉड्यूल] (http://www.doughellmann.com/PyMOTW/subprocess/)। –

+3

ब्लॉग पोस्ट में कई त्रुटियां हैं, उदाहरण के लिए, [पहला कोड उदाहरण: 'कॉल ([' ls ',' -1 '], shell = True) '] (http://www.doughellmann.com/PyMOTW/subprocess /) गलत है। मैं इसके बजाय [subprocess 'टैग विवरण] (http://stackoverflow.com/tags/subprocess/info) से सामान्य प्रश्न पढ़ने की सलाह देते हैं। विशेष रूप से, [क्यों subprocess.Popen काम करता है जब तर्क अनुक्रम है?] (Http://stackoverflow.com/q/2400878/4279) बताता है कि क्यों 'कॉल ([' ls ',' -1 '], खोल = सही) 'गलत है। मुझे ब्लॉग पोस्ट के तहत टिप्पणियां छोड़ना याद है लेकिन मैं उन्हें किसी कारण से नहीं देखता हूं। – jfs

उत्तर

248

Popen.communicate() प्रलेखन:

ध्यान दें कि यदि आप इस प्रक्रिया के stdin को डेटा भेजने के लिए चाहते हैं, तो आप stdin = पाइप के साथ popen वस्तु बनाने की जरूरत है। इसी प्रकार, कुछ भी प्राप्त करने के लिए परिणाम ट्यूपल, में किसी भी अन्य के अलावा आपको stdout = PIPE और/या stderr = PIPE भी देना होगा।

*

pipe = os.popen(cmd, 'w', bufsize) 
    # ==> 
    pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin 

चेतावनी उपयोग संवाद() के बजाय stdin.write(), stdout.read() या stderr.read से os.popen की जगह() डेडलॉक्स से बचने के लिए अन्य ओएस पाइप बफर बच्चे को प्रक्रिया भरने और अवरुद्ध करने के लिए।

तो अपने उदाहरण इस प्रकार लिखा जा सकता है:

from subprocess import Popen, PIPE, STDOUT 

p = Popen(['grep', 'f'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)  
grep_stdout = p.communicate(input=b'one\ntwo\nthree\nfour\nfive\nsix\n')[0] 
print(grep_stdout.decode()) 
# -> four 
# -> five 
# -> 

वर्तमान अजगर 3 संस्करण पर, आप एक बाहरी कमांड के लिए एक स्ट्रिंग के रूप subprocess.run इस्तेमाल कर सकते हैं, इनपुट पारित करने के लिए और पाने के अपने बाहर निकलने की स्थिति, और एक कॉल में वापस एक स्ट्रिंग के रूप में अपनी उत्पादन:

#!/usr/bin/env python3 
from subprocess import run, PIPE 

p = run(['grep', 'f'], stdout=PIPE, 
     input='one\ntwo\nthree\nfour\nfive\nsix\n', encoding='ascii') 
print(p.returncode) 
# -> 0 
print(p.stdout) 
# -> four 
# -> five 
# -> 
+3

मुझे उस चेतावनी को याद आया। मुझे खुशी है कि मैंने पूछा (भले ही मैंने सोचा कि मेरा जवाब है)। –

+8

यह एक अच्छा समाधान नहीं है। विशेष रूप से, यदि आप ऐसा करते हैं तो आप अतुल्यकालिक रूप से p.stdout.readline आउटपुट को संसाधित नहीं कर सकते हैं क्योंकि आपको पूरे स्टडआउट आने की प्रतीक्षा करनी होगी। यह स्मृति-अक्षम भी है। – OTZ

+5

@OTZ बेहतर समाधान क्या है? –

34

मैं इस समाधान का पता लगा?

+6

यह एक कामकाज नहीं है - यह करने का सही तरीका है! – Moe

+17

@Moe: 'stdin.write()' उपयोग को हतोत्साहित किया गया है, 'p.communicate() 'का उपयोग किया जाना चाहिए। मेरा जवाब देखें – jfs

+8

सबप्रोसेस दस्तावेज के अनुसार: चेतावनी - अन्य प्रक्रियाओं को भरने और अवरुद्ध करने वाले किसी अन्य ओएस पाइप बफर के कारण डेडलॉक्स से बचने के लिए .stdin.write, .stdout.read या .stderr.read के बजाय संवाद() का उपयोग करें। –

12

:-)

मैं नहीं डर लग रहा है "जाहिर है एक cStringIO.StringIO वस्तु एक फ़ाइल बतख subprocess.Popen सूट करने के लिए करने के लिए पर्याप्त पास नीम हकीम नहीं है"। पाइप एक निम्न-स्तरीय ओएस अवधारणा है, इसलिए इसे पूरी तरह से एक फ़ाइल ऑब्जेक्ट की आवश्यकता होती है जिसे ओएस-स्तरीय फ़ाइल डिस्क्रिप्टर द्वारा दर्शाया जाता है। आपका कामकाज सही है।

2
p = Popen(['grep', 'f'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)  
p.stdin.write('one\n') 
time.sleep(0.5) 
p.stdin.write('two\n') 
time.sleep(0.5) 
p.stdin.write('three\n') 
time.sleep(0.5) 
testresult = p.communicate()[0] 
time.sleep(0.5) 
print(testresult) 
9
from subprocess import Popen, PIPE 
from tempfile import SpooledTemporaryFile as tempfile 
f = tempfile() 
f.write('one\ntwo\nthree\nfour\nfive\nsix\n') 
f.seek(0) 
print Popen(['/bin/grep','f'],stdout=PIPE,stdin=f).stdout.read() 
f.close() 
+3

fyi, tempfile.SpooledTemporaryFile .__ doc__ कहता है: अस्थायी फ़ाइल रैपर, से स्विच करने के लिए विशिष्ट है जब एक निश्चित फ़ाइल या पर एक वास्तविक फ़ाइल से अधिक होता है जब एक फिलीनो की आवश्यकता होती है। –

6
""" 
Ex: Dialog (2-way) with a Popen() 
""" 

p = subprocess.Popen('Your Command Here', 
       stdout=subprocess.PIPE, 
       stderr=subprocess.STDOUT, 
       stdin=PIPE, 
       shell=True, 
       bufsize=0) 
p.stdin.write('START\n') 
out = p.stdout.readline() 
while out: 
    line = out 
    line = line.rstrip("\n") 

    if "WHATEVER1" in line: 
     pr = 1 
     p.stdin.write('DO 1\n') 
     out = p.stdout.readline() 
     continue 

    if "WHATEVER2" in line: 
     pr = 2 
     p.stdin.write('DO 2\n') 
     out = p.stdout.readline() 
     continue 
""" 
.......... 
""" 

out = p.stdout.readline() 

p.wait() 
+3

क्योंकि 'खोल = ट्रू' का उपयोग आमतौर पर किसी भी अच्छे कारण के लिए नहीं किया जाता है, और यह एक लोकप्रिय सवाल है, मुझे यह बताएं कि ऐसी कई स्थितियां हैं जहां 'पॉपन ([' cmd ',' with ',' args ' ]) '' पॉपन ('args के साथ cmd', shell = True) से निश्चित रूप से बेहतर है, और शैल को कमांड और तर्क टोकन में तोड़ना है, लेकिन अन्यथा कुछ भी उपयोगी नहीं है, जबकि जटिलता की एक महत्वपूर्ण मात्रा जोड़ना और इस प्रकार भी हमले की सतह। – tripleee

5

खबरदार अगर s,, बहुत बड़ा है क्योंकि जाहिरा तौर पर माता पिता प्रक्रिया यह से पहले बफ़र होगा बच्चे उपप्रक्रिया forking जिसका अर्थ यह है कि बिंदु पर की जरूरत है "दो बार के रूप में ज्यादा" का इस्तेमाल किया याद है कि Popen.communicate(input=s) आप मुसीबत दे सकता है (कम से कम "हुड के तहत" स्पष्टीकरण और लिंक किए गए दस्तावेज के अनुसार here मिला)। मेरी विशेष मामले में, s एक जनरेटर है कि पहले पूरी तरह से विस्तृत और उसके बाद ही stdin लिए लिखा गया था तो माता पिता प्रक्रिया विशाल सही से पहले बच्चे को जन्म दिया गया था था, और कोई स्मृति यह कांटा करने के लिए छोड़ दिया गया था:

File "/opt/local/stow/python-2.7.2/lib/python2.7/subprocess.py", line 1130, in _execute_child self.pid = os.fork() OSError: [Errno 12] Cannot allocate memory

14

मैं python3 उपयोग कर रहा हूँ और पता चला है कि आप अपने स्ट्रिंग एन्कोड करने के लिए इससे पहले कि आप stdin में पारित कर सकते हैं की जरूरत है:

p = Popen(['grep', 'f'], stdout=PIPE, stdin=PIPE, stderr=PIPE) 
out, err = p.communicate(input='one\ntwo\nthree\nfour\nfive\nsix\n'.encode()) 
print(out) 
+4

आपको इनपुट को एन्कोड करने की विशेष रूप से आवश्यकता नहीं है, यह केवल बाइट्स जैसी ऑब्जेक्ट चाहता है (उदा। 'B'something'')। यह बाइट्स के रूप में गलती और बाहर लौट आएगा। यदि आप इससे बचना चाहते हैं, तो आप 'universal_newlines = True' को 'popen'' पास कर सकते हैं। फिर यह स्ट्र के रूप में इनपुट स्वीकार करेगा और स्ट्र के रूप में त्रुटि/बाहर वापस आ जाएगा। – Six

+2

लेकिन सावधान रहें, 'universal_newlines = True' आपके सिस्टम से मेल खाने के लिए आपकी नई लाइनों को भी परिवर्तित करेगा – Nacht

+1

यदि आप पाइथन 3 का उपयोग कर रहे हैं, तो [मेरा उत्तर] (http://stackoverflow.com/a/41036665/247696) यहां तक ​​कि यहां तक ​​कि अधिक सुविधाजनक समाधान। – Flimm

17

मैं थोड़ा हैरान कर कोई भी एक पाइप, जो मेरी राय में दूर है बनाने सुझाव दिया हूँ एक स्ट्रिंग को stdin पास करने के लिए सबसे आसान तरीका एक उपप्रक्रिया:

read, write = os.pipe() 
os.write(write, "stdin input here") 
os.close(write) 

subprocess.check_call(['your-command'], stdin=read) 
+1

'ओएस' और 'सबप्रोसेस' दस्तावेज दोनों सहमत हैं कि आपको बाद वाले को प्राथमिकता देना चाहिए। यह एक विरासत समाधान है जिसमें एक मानक (थोड़ा कम संक्षेप) मानक प्रतिस्थापन है; स्वीकृत उत्तर प्रासंगिक दस्तावेज उद्धृत करता है। – tripleee

+1

मुझे यकीन नहीं है कि यह सही है, तीन गुना।उद्धृत दस्तावेज कहता है कि प्रक्रिया द्वारा बनाए गए पाइप का उपयोग करना क्यों मुश्किल है, लेकिन इस समाधान में यह एक पाइप बनाता है और इसे पास करता है। मेरा मानना ​​है कि यह प्रक्रिया शुरू होने के बाद पाइप के प्रबंधन की संभावित डेडलॉक समस्याओं से बचाती है। –

+0

os.popen subprocess – hd1

9

एक खूबसूरत समाधान नहीं है अगर तुम अजगर 3.4 या बेहतर उपयोग कर रहे हैं। जो एक बाइट तर्क स्वीकार करता है stdin तर्क के बजाय input तर्क, का उपयोग करें:

output = subprocess.check_output(
    ["sed", "s/foo/bar/"], 
    input=b"foo", 
) 
+0

'कॉल' – vidstige

+1

@ vidstige के लिए काम नहीं करता है आप सही हैं, यह अजीब है। मैं इसे पाइथन बग के रूप में दर्ज करने पर विचार करता हूं, मुझे कोई अच्छा कारण नहीं दिख रहा है कि 'check_output' में' इनपुट 'तर्क क्यों होना चाहिए, लेकिन' कॉल 'नहीं। – Flimm