আমি কীভাবে সাবপ্রসেসে স্ট্রিং পাস করব? পোপেন (স্ট্যান্ডিন আর্গুমেন্ট ব্যবহার করে)?


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'

স্পষ্টতই একটি স্ট্রিংআইও.স্ট্রিংআইও অবজেক্ট সাব-প্রসেস.পোপেনের জন্য উপযুক্ত ফাইল ফলের হাঁসের কাছে যথেষ্ট পরিমাণে কোঁক দেয় না। আমি কীভাবে এটিকে ঘিরে কাজ করব?


3
এটি মুছে ফেলার সাথে আমার উত্তরটিকে বিতর্ক করার পরিবর্তে, আমি এটি একটি মন্তব্য হিসাবে যুক্ত করছি ... প্রস্তাবিত পড়া: ডগ হেলম্যানের সাবপ্রসেসে ব্লগ পোস্টের পাইথন মডিউল
ড্যারিল স্পিজিটর

3
ব্লগ পোস্টে একাধিক ত্রুটি রয়েছে যেমন, প্রথম কোডের উদাহরণ:call(['ls', '-1'], shell=True) ভুল। পরিবর্তে সাব-প্রসেসের ট্যাগ বিবরণ থেকে সাধারণ প্রশ্নগুলি পড়ার পরামর্শ দিই । বিশেষত, উপ-প্রসেস.পোপেন কেন কাজ করে না যখন অর্গগুলি ক্রম হয়? call(['ls', '-1'], shell=True)ভুল কেন ব্যাখ্যা করে । আমার মনে আছে ব্লগ পোস্টের নীচে মন্তব্য করা কিন্তু আমি এখন কোনও কারণে এগুলি দেখতে পাচ্ছি না।
jfs

উত্তর:


326

Popen.communicate() ডকুমেন্টেশন:

মনে রাখবেন যে আপনি যদি প্রক্রিয়াটির স্টিডিনে ডেটা প্রেরণ করতে চান তবে আপনাকে stdin = PIPE দিয়ে পপেন অবজেক্ট তৈরি করতে হবে। একইভাবে, ফলশ্রুতিতে টিপল ছাড়া অন্য কিছুই পাওয়ার জন্য আপনাকে stdout = PIPE এবং / অথবা stderr = PIPEও দিতে হবে।

Os.popen * প্রতিস্থাপন করা হচ্ছে

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

সতর্কতা ব্যবহার করে অন্য কোনও ওএস পাইপ বাফার বাচ্চার প্রক্রিয়া পূরণ এবং অবরুদ্ধ করার কারণে ডেডলকগুলি এড়াতে stdin.writ (), stdout.read () বা stderr.read () এর পরিবর্তে যোগাযোগ করুন ()।

সুতরাং আপনার উদাহরণ নিম্নরূপ লেখা যেতে পারে:

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
এটি একটি ভাল সমাধান নয়। বিশেষত, আপনি পিএসটিডআউটড্রেডলাইন আউটপুটটি অবিচ্ছিন্নভাবে প্রক্রিয়া করতে পারবেন না যেহেতু আপনাকে পুরো স্টাডাউটের আগমনের জন্য অপেক্ষা করতে হবে। এটি স্মৃতিশক্তি-অদক্ষও।
ওটিজেড

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.writ, .stdout.read বা। Stderr.read এর পরিবর্তে যোগাযোগ () ব্যবহার করুন।
জেসন মক

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
আমি নিশ্চিত না যে এটি সঠিক, ট্রিপলি। উদ্ধৃত ডকুমেন্টেশন বলছে যে প্রক্রিয়াটি দ্বারা নির্মিত পাইপগুলি কেন ব্যবহার করা কঠিন, তবে এই সমাধানে এটি একটি পাইপ তৈরি করে এটি পাস করে I
গ্রাহাম ক্রিস্টেনসেন

os.popen এর subprocess পক্ষে অবচিত
HD1

2
-1: এটি অচলাবস্থার দিকে নিয়ে যায়, এটি ডেটা আলগা করতে পারে। এই কার্যকারিতা ইতিমধ্যে সাবপ্রসেস মডিউল দ্বারা সরবরাহ করা হয়েছে। এটি খারাপভাবে পুনর্বিবেচনা না করে এটি ব্যবহার করুন (কোনও ওএস পাইপ বাফারের চেয়ে বড় যে কোনও মান লেখার চেষ্টা করুন)
জেএফএস

আপনি সেরা ভাল মানুষ প্রাপ্য, সহজ এবং চতুর সমাধানের জন্য আপনাকে ধন্যবাদ
ফিলিপ বুকিওনি

21

আপনি পাইথন ৩.৪ বা আরও বেশি ব্যবহার করতে পারলে একটি সুন্দর সমাধান রয়েছে। inputআর্গুমেন্টের পরিবর্তে যুক্তিটি ব্যবহার করুন stdin, যা একটি বাইট আর্গুমেন্ট গ্রহণ করে:

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

এটি কাজ করে check_outputএবং run, তবে না callবা check_callকোনও কারণে।


5
@vidstige আপনি ঠিক বলেছেন, এটি অদ্ভুত। আমি এটি পাইথন বাগ হিসাবে ফাইল করার বিষয়টি বিবেচনা করব, কেন তর্ক check_outputথাকতে হবে তার কোনও ভাল কারণ আমি দেখতে পাচ্ছি না input, তবে তা নয় call
ফ্লাটম

2
এটি পাইথন ৩.৪++ এর সেরা উত্তর (এটি পাইথন ৩.6 এ ব্যবহার করে)। এটি সত্যিই সাথে কাজ করে না check_callকিন্তু এটি জন্য কাজ করে run। ডকুমেন্টেশন অনুসারে আপনি কোনও এনকোডিং আর্গুমেন্ট পাস করার পরে এটি ইনপুট = স্ট্রিংয়ের সাথেও কাজ করে।
নিকোলোস জর্জিউ

13

আমি পাইথন 3 ব্যবহার করছি এবং জানতে পেরেছি যে আপনি স্ট্রিনে প্রবেশের আগে আপনার স্ট্রিংটি এনকোড করা দরকার:

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। তারপরে এটি স্ট্রিং হিসাবে ইনপুট গ্রহণ করবে এবং ত্রুটি হিসাবে আউট / আউটও আসবে।
ছয়

2
তবে সাবধান, universal_newlines=Trueআপনার সিস্টেমে ম্যাচ করার জন্য আপনার নতুন লাইনগুলিকে রূপান্তর করবে
নচট - মনিকা পুনরায়

1
আপনি যদি পাইথন 3 ব্যবহার করেন তবে আরও বেশি সুবিধাজনক সমাধানের জন্য আমার উত্তরটি দেখুন।
ফ্লিম

12

স্পষ্টতই একটি স্ট্রিংআইও.আর স্ট্রিংআইও অবজেক্ট সাব-প্রসেস.পোপেন অনুসারে ফাইল হাঁসের কাছে পর্যাপ্ত পরিমাণে ঘাঁটাঘাঁটি করে না

আমার ভয় হচ্ছে না. পাইপটি একটি নিম্ন-স্তরের ওএস ধারণা, সুতরাং এটির জন্য একেবারে কোনও ফাইলের প্রয়োজন যা কোনও ওএস-স্তরের ফাইল বর্ণনাকারী দ্বারা প্রতিনিধিত্ব করা হয়। আপনার কর্মক্ষেত্রটি সঠিক।


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করতে চান একটি স্ট্রিং হিসাবে কমান্ড চালানোর আউটপুট পেতে।

Python- র পুরোনো সংস্করণগুলি তারিখে, প্রতিস্থাপন text=Trueসঙ্গে universal_newlines=True:

subprocess.run(["grep", "f"], universal_newlines=True, input=my_data)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.