मैं सबप्रोसेस में एक स्ट्रिंग कैसे पास कर सकता हूं।


280

यदि मैं निम्नलिखित कार्य करता हूं:

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 ऑब्जेक्ट उपप्रकार के अनुरूप एक फ़ाइल को बंद करने के लिए पर्याप्त नहीं है। मैं इसके आसपास कैसे काम करूं?


3
मेरे उत्तर को नष्ट किए जाने के साथ विवादित करने के बजाय, मैं इसे टिप्पणी के रूप में जोड़ रहा हूं ... अनुशंसित पढ़ने: उपप्रकार पर सप्ताह ब्लॉग पोस्ट के डॉग हेलमैन के पायथन मॉड्यूल
डेरिल स्पिट्जर

3
ब्लॉग पोस्ट में कई त्रुटियां हैं उदाहरण के लिए, बहुत पहले कोड उदाहरण:call(['ls', '-1'], shell=True) गलत है। मैं इसके बजाय उपप्रकार टैग विवरण से सामान्य प्रश्न पढ़ने की सलाह देता हूं । विशेष रूप से, क्यों subprocess.Popen काम नहीं करता है जब args अनुक्रम है? बताते हैं कि call(['ls', '-1'], shell=True)गलत क्यों है। मुझे याद है कि मैं ब्लॉग पोस्ट के तहत टिप्पणियां छोड़ता हूं, लेकिन मैं उन्हें किसी कारण से नहीं देखता हूं।
jfs

नए subprocess.runदेखने के लिए stackoverflow.com/questions/48752152/…
बोरिस

जवाबों:


326

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

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

Os.popen की जगह *

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

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

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

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
मुझे वह चेतावनी याद आ गई। मुझे खुशी है कि मैंने पूछा (हालांकि मुझे लगा कि मेरे पास जवाब है)।
डेरिल स्पिट्जर

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

7
@OTZ एक बेहतर उपाय क्या है?
निक टी

11
@ टिक टी: " बेहतर " संदर्भ पर निर्भर करता है। न्यूटन के नियम उन डोमेन के लिए अच्छे हैं जो वे लागू हैं लेकिन आपको जीपीएस डिजाइन करने के लिए विशेष सापेक्षता की आवश्यकता है। अजगर में एक subprocess.PIPE पर गैर-अवरोधक पढ़ा देखें ।
JFS

9
लेकिन संचार के लिए नोट पर ध्यान दें : "यदि डेटा का आकार बड़ा या असीमित है, तो इस विधि का उपयोग न करें"
ओवेन

44

मुझे यह समझ में आया:

>>> 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()

क्या कोई बेहतर है?


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

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

1
मुझे लगता है कि ऐसा करने का यह एक अच्छा तरीका है यदि आपको विश्वास है कि आपका स्टडआउट / इरेट कभी भी नहीं भरेगा (उदाहरण के लिए, यह किसी फ़ाइल में जा रहा है, या कोई अन्य थ्रेड इसे खा रहा है) और आपके पास डेटा की एक अनबाउंड राशि है स्टडिन को भेजा जाना।
लुसट्रिएल

1
विशेष रूप से, इसे इस तरह से करना अभी भी सुनिश्चित करता है कि स्टड बंद हो गया है, ताकि यदि उपप्रकार एक है जो हमेशा के लिए इनपुट का उपभोग करता है, communicateतो पाइप को बंद कर देगा और प्रक्रिया को इनायत से समाप्त करने की अनुमति देगा।
ल्यूक्रिएल

@ ल्यूक्रिएल, यदि प्रक्रिया हमेशा के लिए स्टड का उपभोग करती है, तो संभवतः यह अभी भी हमेशा के लिए स्टडआउट लिख सकता है, इसलिए हमें पूरी तरह से अलग-अलग तकनीकों की आवश्यकता होगी ( read()यह से नहीं, जैसा communicate()कि बिना किसी तर्क के भी होता है)।
चार्ल्स डफी

25

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

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

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

2
osऔर subprocessप्रलेखन दोनों सहमत हैं कि आप पूर्व के ऊपर उत्तरार्द्ध को प्राथमिकता देनी चाहिए। यह एक विरासत समाधान है जिसमें एक (थोड़ा कम संक्षिप्त) मानक प्रतिस्थापन है; स्वीकार किए जाते हैं उत्तर में प्रासंगिक दस्तावेज उद्धरण।
ट्रिपल

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

os.popen सबप्रोसेस के पक्ष में पदावनत है
एचडी 1

2
-1: यह गतिरोध की ओर जाता है, यह डेटा को ढीला कर सकता है। यह कार्यक्षमता पहले से ही सबप्रोसेस मॉड्यूल द्वारा प्रदान की गई है। इसे खराब तरीके से लागू करने के बजाय इसका उपयोग करें (एक ऐसा मान लिखने की कोशिश करें जो OS पाइप बफर से बड़ा हो)
jfs

आप सबसे अच्छे आदमी के लायक हैं, सबसे सरल और चतुर समाधान के लिए धन्यवाद
फेलिप बुकेओनी

21

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

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

यह काम करता है check_outputऔर किसी कारण के लिए या runनहीं ।callcheck_call


5
@vidstige तुम सही हो, यह अजीब है। मैं इसे पायथन बग के रूप में दर्ज करने पर विचार करूंगा, मुझे check_outputकोई inputतर्क नहीं होना चाहिए कि इसमें तर्क क्यों है, लेकिन नहीं call
फ्लिम

2
यह पायथन 3.4+ (पायथन 3.6 में इसका उपयोग) के लिए सबसे अच्छा जवाब है। यह वास्तव में साथ काम नहीं करता है check_callलेकिन यह काम करता है run। यह इनपुट = स्ट्रिंग के साथ भी काम करता है जब तक कि आप प्रलेखन के अनुसार एक एन्कोडिंग तर्क भी पास कर देते हैं।
निकोलोस जॉर्जीऊ

13

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

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)

5
आपको विशेष रूप से इनपुट को एन्कोड करने की आवश्यकता नहीं है, यह सिर्फ एक बाइट्स जैसी ऑब्जेक्ट (जैसे b'something') चाहता है। यह गलत तरीके से और बाइट्स के रूप में भी वापस आ जाएगा। आप इस से बचना चाहते हैं, तो आप पास कर सकते हैं universal_newlines=Trueकरने के लिए Popen। तब यह इनपुट को str के रूप में स्वीकार करेगा और साथ ही साथ str / out को भी लौटाएगा।
छह

2
लेकिन सावधान रहना, universal_newlines=Trueअपने सिस्टम से मेल खाने के लिए आपकी नई कहानियों को भी बदल देगा
नट - मोनिका

1
यदि आप पायथन 3 का उपयोग कर रहे हैं, तो मेरे उत्तर को और भी अधिक सुविधाजनक समाधान के लिए देखें।
फ्लि‍म डिक

12

जाहिरा तौर पर एक cStringIO.StringIO ऑब्जेक्ट उपप्रकार के अनुरूप एक फ़ाइल के करीब पर्याप्त रूप से बंद नहीं करता है। खोलें

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


7
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__ कहते हैं: अस्थायी फ़ाइल आवरण, जो एक निश्चित फ़ाइल से अधिक होने पर या किसी फ़िनलो की आवश्यकता होने पर स्ट्रिंग से वास्तविक फ़ाइल में स्विच करने के लिए विशेष।
डग एफ

5

Popen.communicate(input=s)अगर आपको परेशानी हो तो सावधान रहेंs बहुत बड़ा है, क्योंकि जाहिर है कि माता-पिता की प्रक्रिया बच्चे को उपप्रकार करने से पहले इसे बफर कर देगी , इसका मतलब है कि उस बिंदु पर "दो बार जितनी" स्मृति का इस्तेमाल किया गया है (कम से कम "हुड के तहत" स्पष्टीकरण के अनुसार) और लिंक किए गए प्रलेखन पाया यहाँ )। मेरे विशेष मामले में, 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


5
"""
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()

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

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)

1

पायथन 3.7+ पर ऐसा करें:

my_data = "whatever you want\nshould match this f"
subprocess.run(["grep", "f"], text=True, input=my_data)

और आप capture_output=Trueकमांड को स्ट्रिंग के रूप में चलाने के आउटपुट प्राप्त करने के लिए जोड़ना चाहते हैं ।

पायथन के पुराने संस्करणों पर, इसके text=Trueसाथ बदलें universal_newlines=True:

subprocess.run(["grep", "f"], universal_newlines=True, input=my_data)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.