সাবপ্রসেস কমান্ড থেকে লাইভ আউটপুট


184

আমি হাইড্রোডাইনামিক্স কোডের জন্য ড্রাইভার হিসাবে পাইথন স্ক্রিপ্টটি ব্যবহার করছি। যখন সিমুলেশন চালানোর সময় আসে তখন আমি subprocess.Popenকোডটি চালাতে, স্টডআউট এবং স্টার্ডার থেকে আউটপুট সংগ্রহ করে একটি subprocess.PIPE--- তারপর আমি আউটপুট তথ্য মুদ্রণ করতে (এবং একটি লগ-ফাইলে সংরক্ষণ করতে পারি), এবং কোনও ত্রুটি পরীক্ষা করতে পারি । সমস্যাটি হচ্ছে, কোডটি কীভাবে এগিয়ে চলছে সে সম্পর্কে আমার কোনও ধারণা নেই। যদি আমি এটি কমান্ড লাইন থেকে সরাসরি চালিত করি তবে এটি আমাকে কোন পুনরাবৃত্তির সময়, কোন সময়, পরবর্তী সময়-পদক্ষেপ ইত্যাদি সম্পর্কে আউটপুট দেয়

উভয়ই আউটপুট (লগিং এবং ত্রুটি পরীক্ষার জন্য) সঞ্চয় করার কোনও উপায় আছে এবং লাইভ স্ট্রিমিং আউটপুটও উত্পাদন করে?

আমার কোড সম্পর্কিত বিভাগ:

ret_val = subprocess.Popen( run_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True )
output, errors = ret_val.communicate()
log_file.write(output)
print output
if( ret_val.returncode ):
    print "RUN failed\n\n%s\n\n" % (errors)
    success = False

if( errors ): log_file.write("\n\n%s\n\n" % errors)

মূলত আমি বংশীধ্বনিতুল্য ছিল run_commandমাধ্যমে teeযাতে একটি কপি লগ-ফাইলের সঙ্গে সরাসরি গিয়েছিলাম, এবং স্ট্রিম এখনও আউটপুট সরাসরি টার্মিনালে - কিন্তু যে ভাবে (আমার knowlege করার জন্য) আমি কোনো ত্রুটি না সংরক্ষণ করতে পারেন।


সম্পাদনা:

অস্থায়ী সমাধান:

ret_val = subprocess.Popen( run_command, stdout=log_file, stderr=subprocess.PIPE, shell=True )
while not ret_val.poll():
    log_file.flush()

তারপরে, অন্য টার্মিনালে, চালাও tail -f log.txt(স্টেট log_file = 'log.txt')।


1
সম্ভবত আপনি আগের স্ট্যাক ওভারফ্লো প্রশ্নPopen.poll হিসাবে ব্যবহার করতে পারেন ।
পাওলো আলমেইদা

কিছু কমান্ড যা অগ্রগতির ইঙ্গিত দেয় (যেমন, git) কেবল তখনই যদি তাদের আউটপুটটি "টিটিআই ডিভাইস" হয় (লিব্যাকের মাধ্যমে পরীক্ষিত হয় isatty())। সেক্ষেত্রে আপনাকে সিডো-টিটিটি খুলতে হতে পারে।
টেরিক

@ টোরেক কি (সিউডো-) টিটি?
ডিলিথিয়ামম্যাট্রিক্স

2
ইউনিক্সের মতো সিস্টেমে থাকা ডিভাইসগুলি যা কোনও প্রক্রিয়াটিকে সিরিয়াল পোর্টে ব্যবহারকারী হওয়ার ভান করার অনুমতি দেয়। উদাহরণস্বরূপ ssh (সার্ভার সাইড) এইভাবে কাজ করে। পাইথন পিটিআই লাইব্রেরি দেখুন এবং এক্সপেক্টও করুন
টেরিক

পুনরায় সাময়িক সমাধান আছে: কল করার কোন প্রয়োজন flush, এবং হয় দ্বারা stderr নল থেকে পড়তে যদি subprocess অনেক দ্বারা stderr আউটপুট উত্পাদন করে প্রয়োজন নেই। এটি ব্যাখ্যা করার জন্য কোনও মন্তব্যে যথেষ্ট জায়গা নেই ...
টেরিক

উত্তর:


168

আপনার এটি করার দুটি উপায় রয়েছে হয় হয় কার্য readবা একটি readlineফাংশন থেকে একটি পুনরুক্তি তৈরি করে এবং করুন:

import subprocess
import sys
with open('test.log', 'w') as f:  # replace 'w' with 'wb' for Python 3
    process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
    for c in iter(lambda: process.stdout.read(1), ''):  # replace '' with b'' for Python 3
        sys.stdout.write(c)
        f.write(c)

অথবা

import subprocess
import sys
with open('test.log', 'w') as f:  # replace 'w' with 'wb' for Python 3
    process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
    for line in iter(process.stdout.readline, ''):  # replace '' with b'' for Python 3
        sys.stdout.write(line)
        f.write(line)

অথবা আপনি একটি readerএবং একটি writerফাইল তৈরি করতে পারেন । পাশ writerথেকে Popenএবং থেকে পড়াreader

import io
import time
import subprocess
import sys

filename = 'test.log'
with io.open(filename, 'wb') as writer, io.open(filename, 'rb', 1) as reader:
    process = subprocess.Popen(command, stdout=writer)
    while process.poll() is None:
        sys.stdout.write(reader.read())
        time.sleep(0.5)
    # Read the remaining
    sys.stdout.write(reader.read())

এইভাবে আপনার test.logস্ট্যান্ডার্ড আউটপুটে পাশাপাশি ডেটা লেখা থাকবে ।

ফাইল পদ্ধতির একমাত্র সুবিধা হ'ল আপনার কোডটি ব্লক করে না। সুতরাং আপনি এর মধ্যে যা খুশি তা করতে পারেন এবং যখনই আপনি চাইবেন readerনা-অবরুদ্ধ উপায়ে পড়ুন। আপনি যখন ব্যবহার করবেন PIPE, readএবং readlineফাংশনগুলি অবরুদ্ধ হবে যতক্ষণ না পাইপটিতে একটি করে অক্ষর লেখা হয় বা পাইপটিতে যথাক্রমে একটি লাইন না লেখা হয়।


1
উঘ :-) কোনও ফাইলে লিখুন, তা থেকে পড়ুন, এবং লুপটিতে ঘুমাবেন? ফাইলটি পড়া শেষ করার আগে প্রক্রিয়াটি শেষ হওয়ারও একটি সুযোগ রয়েছে।
গাই স্যারটন

13
পাইথন 3, আপনি প্রয়োজন iter(process.stdout.readline, b'')(অর্থাত প্রহরী প্রেরণ রাউটার একটি বাইনারি স্ট্রিং হতে করে নেওয়া প্রয়োজন এমন যেহেতু b'' != ''
জন Mellor

3
: বাইনারি স্ট্রিম জন্য, এই নাfor line in iter(process.stdout.readline, b''): sys.stdout.buffer.write(line)
rrlamichhane

6
পাইথন 3-এ @ জনমেলরের উত্তর যুক্ত করাতে নিম্নলিখিত পরিবর্তনগুলির প্রয়োজন ছিল: process = subprocess.Popen(command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE) for line in iter(process.stdout.readline, b'') sys.stdout.write(line.decode(sys.stdout.encoding))
বেরেজরুকি

4
তবে আউটপুট লাইভ হয় না, তাই না? আমার অভিজ্ঞতায়, প্রক্রিয়াটি শেষ হওয়া পর্যন্ত এটি অপেক্ষা করে এবং কেবলমাত্র কনসোলটিতে মুদ্রণ করে। লিংক -> stackoverflow.com/questions/30026045/...
denis631

91

এক্সিকিউটিভ সংক্ষিপ্তসার (বা "টিএল; ডাঃ" সংস্করণ): সর্বাধিক একটি রয়েছে যখন এটি সহজ subprocess.PIPE, অন্যথায় এটি শক্ত।

subprocess.Popenএটির জিনিসটি কীভাবে হয় সে সম্পর্কে কিছুটা ব্যাখ্যা করার সময় হতে পারে ।

(ক্যাভিয়েট: এটি পাইথন ২.x এর জন্য, যদিও ৩.x অনুরূপ; এবং আমি উইন্ডোজ ভেরিয়েন্টে বেশ ফাসি। আমি পসিক্স স্টাফটি আরও ভাল বুঝি))

Popenফাংশন শূন্য-টু-তিন ইনপুট / আউটপুট স্ট্রিম, কিছুটা একযোগে সাথে মোকাবিলা করতে হবে। এই প্রকাশ করা হয় stdin, stdoutএবং stderrযথারীতি।

আপনি প্রদান করতে পারেন:

  • Noneএটি নির্দেশ করে যে আপনি স্ট্রিমটি পুনর্নির্দেশ করতে চান না। পরিবর্তে এটি যথারীতি এগুলির উত্তরাধিকারী হবে। নোট করুন যে POSIX সিস্টেমে কমপক্ষে, এর অর্থ এই নয় যে এটি পাইথনের ব্যবহার করবে sys.stdout, কেবল পাইথনের আসল স্টাডআউট; শেষে ডেমো দেখুন।
  • একটি intমান। এটি একটি "কাঁচা" ফাইল বর্ণনাকারী (কমপক্ষে POSIX এ)। (পার্শ্ব নোট: PIPEএবং STDOUTপ্রকৃতপক্ষে intঅভ্যন্তরীণভাবে তবে এটি "অসম্ভব" বর্ণনাকারী, -1 এবং -2।)
  • একটি স্ট্রিম — সত্যই, কোনও filenoপদ্ধতি সহ কোনও বস্তু । Popenএই স্ট্রিমটির জন্য বর্ণনাকারীটি ব্যবহার করে খুঁজে পাবেন stream.fileno()এবং তারপরে একটি intমান হিসাবে অগ্রসর হবেন ।
  • subprocess.PIPE, পাইথনের একটি পাইপ তৈরি করা উচিত তা নির্দেশ করে।
  • subprocess.STDOUT( stderrকেবলমাত্র): পাইথনকে একই বর্ণনাকারী হিসাবে ব্যবহার করতে বলুন stdout। এটি কেবল তখনই অর্থবোধ করে যখন আপনি কোনও (অ- None) মান প্রদান করেছেন stdoutএবং তারপরেও, এটি সেট করা থাকলেই এটি প্রয়োজনstdout=subprocess.PIPE । (অন্যথায় আপনি stdoutযেমন সরবরাহ করেছেন ঠিক একই যুক্তি সরবরাহ করতে পারেন , যেমন, Popen(..., stdout=stream, stderr=stream)))

সবচেয়ে সহজ কেস (কোন পাইপ নেই)

যদি আপনি কিছুই পুনর্নির্দেশ করেন (তিনটিই ডিফল্ট Noneমান হিসাবে বা স্পষ্টত সরবরাহ হিসাবে ছেড়ে যান None), Pipeএটি যথেষ্ট সহজ। এটি কেবল সাবপ্রসেসটি বন্ধ করে চালানো দরকার। বা, যদি আপনি কোনও PIPEঅন- intor ান বা স্ট্রিমের to fileno()এটি এখনও সহজ হিসাবে পুনর্নির্দেশ করেন তবে ওএস সমস্ত কাজ করে। পাইথনকে কেবল উপ-প্রসেসটি বন্ধ করে দেওয়া উচিত, এটির স্টিডিন, স্টডআউট এবং / অথবা স্টার্ডার সরবরাহ করা ফাইল বর্ণনাকারীর সাথে সংযুক্ত করে।

এখনও সহজ কেস: একটি পাইপ

আপনি যদি কেবল একটি স্ট্রিম পুনর্নির্দেশ করেন তবে Pipeএখনও জিনিসগুলি বেশ সহজ। আসুন একবারে একটি স্ট্রিম বাছাই করে দেখুন।

মনে করুন আপনি কিছু সরবরাহ করতে চান stdinতবে পুনর্নির্দেশ করুন stdoutএবং stderrযান বা কোনও ফাইল বিবরণীতে যান। অভিভাবক প্রক্রিয়া হিসাবে, পাইথন write()ডেটা প্রেরণের জন্য আপনার পাইথন প্রোগ্রামটি সহজেই ব্যবহার করা দরকার । আপনি নিজে এটি করতে পারেন, যেমন:

proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
proc.stdin.write('here, have some data\n') # etc

অথবা আপনি স্টিডিন ডেটাতে পাস করতে পারেন proc.communicate()যা stdin.writeউপরের দেখায়। কোনও আউটপুট ফিরে আসেনি তাই communicate()কেবল অন্য একটি আসল কাজ রয়েছে: এটি আপনার জন্য পাইপটি বন্ধ করে দেয়। (আপনি যদি কল না করেন তবে proc.communicate()আপনাকে অবশ্যই proc.stdin.close()পাইপটি বন্ধ করার জন্য কল করতে হবে , যাতে সাব-প্রসেসটি জানতে পারে যে এর মাধ্যমে আর কোনও ডেটা আসছে না))

মনে করুন আপনি ক্যাপচার করতে চান stdoutতবে ছেড়ে চলে যান stdinএবং stderrএকা। আবার এটি সহজ: proc.stdout.read()যতক্ষণ না কোনও আউটপুট না আসে কেবল কল (বা সমমান)) যেহেতু proc.stdout()একটি সাধারণ পাইথন আই / ও স্ট্রিম তাই আপনি এটিতে সমস্ত সাধারণ নির্মাণ ব্যবহার করতে পারেন:

for line in proc.stdout:

বা, আবার, আপনি ব্যবহার করতে পারেন proc.communicate(), যা কেবল আপনার read()জন্য করে।

আপনি যদি কেবল ক্যাপচার করতে চান stderrতবে এটি একই সাথে কাজ করে stdout

জিনিসগুলি শক্ত হওয়ার আগে আরও একটি কৌশল আছে। মনে করুন আপনি ক্যাপচার করতে চান stdout, এবং ক্যাপচার করতে চান stderrতবে স্ট্যান্ডআউটের মতো একই পাইপে:

proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

এই ক্ষেত্রে, subprocess"চিটস"! ঠিক আছে, এটি এটি করতে হবে, সুতরাং এটি আসলে প্রতারণা নয়: এটি তার স্টাডাউট এবং তার স্টেডার উভয়কেই (একক) পাইপ-বিবরণীতে নির্দেশিত সাবপ্রসেস শুরু করে যা তার প্যারেন্ট (পাইথন) প্রক্রিয়াতে ফিরে আসে। প্যারেন্ট সাইডে, আউটপুট পড়ার জন্য কেবল আবার একক পাইপ-বর্ণনাকারী রয়েছে। সমস্ত "স্ট্যাডার" আউটপুট প্রদর্শিত হবে proc.stdoutএবং আপনি যদি কল করেন proc.communicate()তবে স্ট্যাডার ফলাফল (টিউপলের দ্বিতীয় মান) হবে Noneস্ট্রিং নয়।

কঠিন ক্ষেত্রে: দুই বা ততোধিক পাইপ

আপনি যখন কমপক্ষে দুটি পাইপ ব্যবহার করতে চান তখন সমস্ত সমস্যা দেখা দেয়। আসলে, subprocessকোড নিজেই এই বিট আছে:

def communicate(self, input=None):
    ...
    # Optimization: If we are only using one pipe, or no pipe at
    # all, using select() or threads is unnecessary.
    if [self.stdin, self.stdout, self.stderr].count(None) >= 2:

তবে হায়, এখানে আমরা কমপক্ষে দু'টি তৈরি করেছি এবং তিনটি ভিন্ন ভিন্ন পাইপ রয়েছে, সুতরাং count(None)1 বা 0 এর রিটার্ন দেয় আমাদের অবশ্যই শক্ত জিনিসগুলি করতে হবে।

Windows এ, এই ব্যবহারের threading.Threadজন্য জমা ফলাফলে self.stdoutএবং self.stderr, এবং পিতা বা মাতা থ্রেড উদ্ধার হয়েছে self.stdinইনপুট ডেটা (এবং তারপর বন্ধ নল)।

পসিক্সে, এটি pollযদি পাওয়া যায় তবে অন্যথায় selectআউটপুট সংগ্রহ করতে এবং স্টিডিন ইনপুট সরবরাহ করতে ব্যবহার করে। এগুলি সমস্ত (একক) প্যারেন্ট প্রসেস / থ্রেডে চলে।

অচলাবস্থা এড়াতে এখানে থ্রেড বা পোল / সিলেক্ট করা দরকার। ধরুন, উদাহরণস্বরূপ, আমরা তিনটি পৃথক পাইপগুলিতে তিনটি স্ট্রিমকে পুনঃনির্দেশিত করেছি। আরও ধরুন যে লেখার প্রক্রিয়াটি স্থগিত হওয়ার আগে পাইপটিতে কতটা তথ্য স্টাফ করা যেতে পারে তার একটি ছোট সীমা রয়েছে, অন্য প্রান্ত থেকে পাইপটি "পরিষ্কার" করার জন্য অপেক্ষা করছেন। আসুন ছোট ছোট সীমাটি একটি মাত্র বাইটে সেট করুন, কেবল উদাহরণের জন্য। (এটি আসলে জিনিসগুলি কীভাবে কাজ করে তা সীমাবদ্ধতা এক বাইটের চেয়ে অনেক বড় except

পিতা বা মাতা (পাইথন) প্রক্রিয়া চেষ্টা বিভিন্ন বাইট-Say, লিখতে পারেন 'go\n'করতে proc.stdin, প্রথম বাইট যায় এবং তারপর দ্বিতীয় পাইথন প্রক্রিয়া ঘটায় স্থগিত করার, subprocess জন্য অপেক্ষা প্রথম বাইট পড়তে, নল খালি।

এদিকে, ধরুন উপ-প্রসেসটি একটি বন্ধুত্বপূর্ণ "হ্যালো! আতঙ্কিত হবেন না!" প্রিন্ট করার সিদ্ধান্ত নিয়েছে অভিবাদন। Hতার stdout- এ পাইপ মধ্যে যায়, কিন্তু eস্থগিত করার এটা কারণ, তার পিতা বা মাতা যে পড়তে অপেক্ষা H, stdout- এ পাইপ খালি।

এখন আমরা আটকে আছি: পাইথন প্রক্রিয়াটি ঘুমিয়ে আছে, "যাও" বলে শেষ করার জন্য অপেক্ষা করছে, এবং উপশহরটিও ঘুমিয়ে আছে, "হ্যালো! আতঙ্কিত হবেন না!" বলে শেষ করার জন্য অপেক্ষা করছেন।

subprocess.Popenকোড থ্রেডিং-অর-নির্বাচন / ভোট সঙ্গে এই সমস্যা এড়াতে। বাইটগুলি পাইপগুলির উপর দিয়ে যেতে পারলে তারা যায়। যখন তারা পারবেন না, কেবল একটি থ্রেড (পুরো প্রক্রিয়া নয়) ঘুমাতে হবে select বা নির্বাচন / পোলের ক্ষেত্রে পাইথন প্রক্রিয়া একই সাথে "অপেক্ষা করতে পারে" বা "উপলব্ধ ডেটা উপলব্ধ" এর জন্য অপেক্ষা করে, প্রক্রিয়াটির স্টিডিনে লিখে কেবল যখন রুম থাকে এবং তার স্টাডআউট এবং / অথবা স্ট্যাডার কেবল তখনই ডেটা প্রস্তুত থাকে reads proc.communicate()কোড (আসলে _communicateযেখানে লোমশ মামলা পরিচালনা করা হয়) আয় সব stdin ডেটা একবার (যদি থাকে) পাঠানো হয়েছে এবং সকল stdout- এ এবং / অথবা দ্বারা stderr ডেটা সঞ্চিত হয়েছে।

যদি আপনি উভয় stdoutএবং stderrদুটি ভিন্ন পাইপ (কোনও stdinপুনর্নির্দেশ নির্বিশেষে ) পড়তে চান তবে আপনারও অচলাবস্থা এড়াতে হবে। এখানে অচলাবস্থার পরিস্থিতিটি ভিন্ন — এটি ঘটে যখন আপনি stderrযখন উপাত্তগুলি থেকে ডেটা টানছেন stdout, বা বিপরীতে long তবে এটি এখনও রয়েছে long


ডেমো

আমি প্রতিশ্রুতি দিয়েছিলাম যে, পুনঃনির্দেশিত, পাইথন subprocessএস অন্তর্নিহিত স্টডআউটকে লিখেছেন, না sys.stdout। সুতরাং, এখানে কিছু কোড:

from cStringIO import StringIO
import os
import subprocess
import sys

def show1():
    print 'start show1'
    save = sys.stdout
    sys.stdout = StringIO()
    print 'sys.stdout being buffered'
    proc = subprocess.Popen(['echo', 'hello'])
    proc.wait()
    in_stdout = sys.stdout.getvalue()
    sys.stdout = save
    print 'in buffer:', in_stdout

def show2():
    print 'start show2'
    save = sys.stdout
    sys.stdout = open(os.devnull, 'w')
    print 'after redirect sys.stdout'
    proc = subprocess.Popen(['echo', 'hello'])
    proc.wait()
    sys.stdout = save

show1()
show2()

যখন রান করুন:

$ python out.py
start show1
hello
in buffer: sys.stdout being buffered

start show2
hello

নোট করুন যে প্রথম রুটিনটি যদি আপনি যুক্ত করেন তবে ব্যর্থ হবে stdout=sys.stdout, কারণ কোনও StringIOবস্তুর কোনও নেই fileno। দ্বিতীয় বর্জন করবে helloযদি আপনি যোগ stdout=sys.stdoutযেহেতু sys.stdoutথেকে আপনাকে পুনঃনির্দেশিত করা হয়েছে os.devnull

(আপনি যদি পাইথনের ফাইল-বিবরণকারী -১ পুনর্নির্দেশ করেন তবে সাব-প্রসেস সেই পুনঃনির্দেশটি অনুসরণ করবে The open(os.devnull, 'w')কলটি এমন একটি প্রবাহ তৈরি করবে যার fileno()পরিমাণ ২ এর চেয়ে বেশি)


হুম। আপনার ডেমোটি শেষ পর্যন্ত দাবির বিপরীত দেখায় বলে মনে হচ্ছে। আপনি পাইথনের স্টাডাউটটিকে বাফারে পুনঃনির্দেশ দিচ্ছেন কিন্তু সাবপ্রসেস স্টাডাউট এখনও কনসোলে চলছে। কিভাবে এটি দরকারী? আমি কিছু অনুপস্থিত করছি?
গাই সিরটন 21

@ গুয়াসিরটন: ডেমো দেখায় যে সাবপ্রসেস স্টাডাউট (যখন স্পষ্টভাবে নির্দেশিত নয় sys.stdout) পাইথনের স্টাডাউটে যায় , পাইথন প্রোগ্রামের ( sys.) স্টাডাউটে নয়। আমি স্বীকার করি যা একটি ... বিজোড় পার্থক্য। এই শব্দগুচ্ছ করার আরও ভাল উপায় আছে?
21

এটি জেনে রাখা ভাল তবে আমরা এখানে সাব-প্রসেস আউটপুটটি ক্যাপচার করতে চাই তাই সিএস.স্টডআউটটি পরিবর্তন করা সহজ তবে আমার মনে করতে আমাদের সহায়তা করে না। যোগাযোগের ভাল পর্যবেক্ষণ অবশ্যই নির্বাচিত (), পোল বা থ্রেড জাতীয় কিছু ব্যবহার করা উচিত।
গাই সিরটন 21


আমি সিলেক্ট ()
সিভান

20

আমরা স্ট্যান্ডআউট পড়ার জন্য ডিফল্ট ফাইল পুনরায় ব্যবহারকারীর ব্যবহারের পরিবর্তে রিডলাইন () দ্বারা ইটার কনস্ট্রাক্ট ব্যবহার করতে পারি না।

import subprocess
import sys
process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
for line in process.stdout:
    sys.stdout.write(line)

এখানে সবচেয়ে মার্জিত উত্তর!
নীড়

9
এই সমাধানটি রিয়েল টাইমে প্রদর্শিত হয় না। প্রক্রিয়াটি শেষ হওয়া পর্যন্ত এটি অপেক্ষা করে এবং একবারে সমস্ত আউটপুট প্রদর্শন করে। ভিক্টর কারকেজের সমাধানে, "আপনার_কম্যান্ড" যদি ক্রমবর্ধমানভাবে প্রদর্শিত হয়, আউটপুটটি পর্যায়ক্রমে অনুসরণ করা হয়, যতক্ষণ না "আপনার_কম্যান্ড" সময়ে সময়ে স্টাডআউট প্রবাহিত হয় (পাইপের কারণে)।
এরিক এইচ।

1
@ নীর এটি লাইভ না থাকায়।
মেলমাস

এই সমাধানটি ডিফল্ট বর্ণনাকারীতে পুনরাবৃত্তি হয়, সুতরাং আউটপুটটিতে কোনও লাইন আপডেট হলেই এটি আপডেট হবে। একটি চরিত্র ভিত্তিক আপডেটের জন্য আপনাকে ভিক্টরের সমাধান হিসাবে প্রদর্শিত () পদ্ধতিতে পুনরাবৃত্তি করতে হবে। তবে এটি আমার ব্যবহারের ক্ষেত্রে ওভারকিল ছিল।
জুগহেড

12

আপনি যদি তৃতীয় পক্ষের লাইব্রেরি ব্যবহার করতে সক্ষম হন তবে আপনি এর মতো কিছু ব্যবহার করতে সক্ষম হতে পারবেন sarge(প্রকাশ: আমি এর রক্ষণাবেক্ষণকারী)। এই গ্রন্থাগারটি সাব-প্রসেসগুলি থেকে আউটপুট স্ট্রিমগুলিতে অ-ব্লকিং অ্যাক্সেসের অনুমতি দেয় - এটি subprocessমডিউলটির উপরে স্তরযুক্ত ।


সরেজ উপর দুর্দান্ত কাজ, বিটিডাব্লু। এটি প্রকৃতপক্ষে ওপি'র প্রয়োজনীয়তা সমাধান করে, তবে ব্যবহারের ক্ষেত্রে এটি কিছুটা ভারী হতে পারে।
-15 এ 15

4

সমাধান 1: লগ stdoutএবং stderrরিয়েলটাইম একযোগে

একটি সহজ সমাধান যা স্টডআউট এবং স্টডার উভয়ই লগ ইন করে, রিয়েলটাইমের লাইন বাই লাইন একটি লগ ফাইলে।

import subprocess as sp
from concurrent.futures import ThreadPoolExecutor


def log_popen_pipe(p, stdfile):

    with open("mylog.txt", "w") as f:

        while p.poll() is None:
            f.write(stdfile.readline())
            f.flush()

        # Write the rest from the buffer
        f.write(stdfile.read())


with sp.Popen(["ls"], stdout=sp.PIPE, stderr=sp.PIPE, text=True) as p:

    with ThreadPoolExecutor(2) as pool:
        r1 = pool.submit(log_popen_pipe, p, p.stdout)
        r2 = pool.submit(log_popen_pipe, p, p.stderr)
        r1.result()
        r2.result()

সমাধান 2: এমন একটি ফাংশন read_popen_pipes()যা আপনাকে একই সাথে রিয়েলটাইমে উভয় পাইপ (স্টাডআউট / স্ট্ডার) দিয়ে পুনরাবৃত্তি করতে দেয়

import subprocess as sp
from queue import Queue, Empty
from concurrent.futures import ThreadPoolExecutor


def enqueue_output(file, queue):
    for line in iter(file.readline, ''):
        queue.put(line)
    file.close()


def read_popen_pipes(p):

    with ThreadPoolExecutor(2) as pool:
        q_stdout, q_stderr = Queue(), Queue()

        pool.submit(enqueue_output, p.stdout, q_stdout)
        pool.submit(enqueue_output, p.stderr, q_stderr)

        while True:

            if p.poll() is not None and q_stdout.empty() and q_stderr.empty():
                break

            out_line = err_line = ''

            try:
                out_line = q_stdout.get_nowait()
                err_line = q_stderr.get_nowait()
            except Empty:
                pass

            yield (out_line, err_line)

# The function in use:

with sp.Popen(my_cmd, stdout=sp.PIPE, stderr=sp.PIPE, text=True) as p:

    for out_line, err_line in read_popen_pipes(p):
        print(out_line, end='')
        print(err_line, end='')

    return p.poll()

3

একটি ভাল তবে "হেভিওয়েট" সমাধানটি টুইস্টেড ব্যবহার করা - নীচের অংশটি দেখুন।

আপনি যদি এই লাইনের সাথে কেবল স্টাডাউট কিছু নিয়ে বাস করতে চান তবে কাজ করা উচিত:

import subprocess
import sys
popenobj = subprocess.Popen(["ls", "-Rl"], stdout=subprocess.PIPE)
while not popenobj.poll():
   stdoutdata = popenobj.stdout.readline()
   if stdoutdata:
      sys.stdout.write(stdoutdata)
   else:
      break
print "Return code", popenobj.returncode

(আপনি যদি পঠন ব্যবহার করেন () এটি পুরো "ফাইল" পড়ার চেষ্টা করে যা দরকারী নয়, যা আমরা এখানে সত্যিই ব্যবহার করতে পারি এটি হ'ল পাইপে থাকা সমস্ত ডেটা এখনই পড়তে পারে)

থ্রেডিংয়ের মাধ্যমেও কেউ এটির কাছে যাওয়ার চেষ্টা করতে পারে, যেমন:

import subprocess
import sys
import threading

popenobj = subprocess.Popen("ls", stdout=subprocess.PIPE, shell=True)

def stdoutprocess(o):
   while True:
      stdoutdata = o.stdout.readline()
      if stdoutdata:
         sys.stdout.write(stdoutdata)
      else:
         break

t = threading.Thread(target=stdoutprocess, args=(popenobj,))
t.start()
popenobj.wait()
t.join()
print "Return code", popenobj.returncode

এখন আমরা দুটি থ্রেড রেখে সম্ভাব্যভাবে স্ট্যাডার যুক্ত করতে পারি।

নোট করুন তবে সাব-প্রসেস ডক্স সরাসরি এই ফাইলগুলি ব্যবহার করে নিরুৎসাহিত করে এবং ব্যবহার করার পরামর্শ দেয় communicate()(বেশিরভাগ ডেডলকগুলির সাথে সম্পর্কিত যা আমি মনে করি যে এটি কোনও সমস্যা নয়) এবং সমাধানগুলি কিছুটা ক্লানকি তাই এটি সত্যিই মনে হচ্ছে সাবপ্রসেস মডিউলটি যথেষ্ট পরিমাণে আপ নয় isn't কাজটি (এছাড়াও দেখুন: http://www.python.org/dev/peps/pep-3145/ ) এবং আমাদের অন্য কিছু দেখার প্রয়োজন।

আরও জড়িত সমাধানটি এখানে দেখানো হিসাবে টুইস্ট ব্যবহার করা হয় : https://twistedmatrix.com/documents/11.1.0/core/howto/process.html

ট্যুইস্টেড দিয়ে আপনি যেভাবে এটি করছেন তা হল আপনার প্রক্রিয়াটি তৈরি করে এমনটিreactor.spawnprocess() সরবরাহ করে ProcessProtocolযা তারপরে অ্যাসিঙ্ক্রোনালি আউটপুট প্রক্রিয়া করে। ট্যুইস্টেড নমুনা পাইথন কোডটি এখানে: https://twistedmatrix.com/documents/11.1.0/core/howto/listings/process/process.py


ধন্যবাদ! আমি শুধু (ভালো কিছু @PauloAlmeida এর মন্তব্যে উপর ভিত্তি করে চেষ্টা করেছি, কিন্তু subprocess.Popen আমার কল করতে অবরুদ্ধ করে - অর্থাৎ এটি শুধুমাত্র যখন লুপ আসে একবার এটি ফেরৎ ...
DilithiumMatrix

1
যা হচ্ছে তা নয়। এটি ঠিক তখনই লুপটি প্রবেশ করছে তখন read()সাবপ্রসেসটি প্রস্থান না হওয়া এবং পাইপটিতে অভিভাবক প্রক্রিয়াটি না পাওয়া পর্যন্ত কলটিতে ব্লক করা EOF
Alp

@ সমস্ত আকর্ষণীয়! সুতরাং এটাই.
ডিলিথিয়ামম্যাট্রিক্স

হ্যাঁ, আমি এটি পোস্ট করতে খুব দ্রুত ছিলাম। এটি আসলে সঠিকভাবে কাজ করে না এবং সহজেই ঠিক করা যায় না। অঙ্কন টেবিল ফিরে।
গাই স্যারটন

1
@ জারমেস: সুতরাং পঠন () এর সাথে সমস্যা হচ্ছে এটি ইওএফ পর্যন্ত পুরো আউটপুটটি পড়ার চেষ্টা করবে যা কার্যকর নয়। রিডলাইন () আপনাকে যা প্রয়োজন তা হ'ল সহায়তা করে এবং হতে পারে (যদিও দীর্ঘ লাইনগুলি যদিও সমস্যা হতে পারে)। আপনি যে প্রক্রিয়াটি চালু করছেন তাতে আপনাকে বাফারিংয়ের জন্যও নজর রাখা দরকার ...
গাই সিরটন

3

এই সমস্ত উত্তর ছাড়াও, একটি সহজ পদ্ধতির নিম্নলিখিত হিসাবেও হতে পারে:

process = subprocess.Popen(your_command, stdout=subprocess.PIPE)

while process.stdout.readable():
    line = process.stdout.readline()

    if not line:
        break

    print(line.strip())

পঠনযোগ্য স্ট্রিমটি যতক্ষণ না এটি পঠনযোগ্য ততক্ষণ লুপ করুন এবং যদি এটি একটি খালি ফলাফল পায় তবে এটি বন্ধ করুন।

এখানে মূল কীটি যদি কোনও আউটপুট এবং খালি খালি থাকে তবে যতক্ষণ না এটি শেষ হয় ততক্ষণ readline()একটি লাইন দেয় ( \nশেষে থাকে)।

আশা করি এটি কাউকে সাহায্য করবে।


3

উপরের সমস্তটির উপর ভিত্তি করে আমি কিছুটা পরিবর্তিত সংস্করণ (পাইথন 3) প্রস্তাব করছি:

  • লুপ কলিং রিডলাইন করার সময় (প্রস্তাবিত সমাধান সমাধানটি আমার জন্য চিরকাল অবরুদ্ধ বলে মনে হয় - পাইথন 3, উইন্ডোজ 7)
  • স্ট্রাক্টর তাই রিড ডেটা হ্যান্ডলিংয়ের জরিপ ফেরতের পরে নকল করার দরকার নেই-None
  • stderr স্টপআউটে পাইপ করা হয়েছে যাতে উভয় আউটপুট আউটপুট পড়ে
  • সেন্টিমিটারের প্রস্থান মূল্য পেতে কোড যুক্ত করা হয়েছে।

কোড:

import subprocess
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
                        stderr=subprocess.STDOUT, universal_newlines=True)
while True:
    rd = proc.stdout.readline()
    print(rd, end='')  # and whatever you want to do...
    if not rd:  # EOF
        returncode = proc.poll()
        if returncode is not None:
            break
        time.sleep(0.1)  # cmd closed stdout, but not exited yet

# You may want to check on ReturnCode here

returncodeঅংশ আমার ক্ষেত্রে অত্যন্ত গুরুত্বপূর্ণ ছিল।
স্টারডাস্ট

2

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

proc = subprocess.Popen(run_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
while proc.poll() is None:
    line = proc.stdout.readline()
    print line
    log_file.write(line + '\n')
# Might still be data on stdout at this point.  Grab any
# remainder.
for line in proc.stdout.read().split('\n'):
    print line
    log_file.write(line + '\n')
# Do whatever you want with proc.stderr here...

2

কেন stdoutসরাসরি সেট করা হয় না sys.stdout? এবং যদি আপনার পাশাপাশি একটি লগতে আউটপুট প্রয়োজন হয়, তবে আপনি কেবল চ এর রাইটিং পদ্ধতিটি ওভাররাইড করতে পারেন।

import sys
import subprocess

class SuperFile(open.__class__):

    def write(self, data):
        sys.stdout.write(data)
        super(SuperFile, self).write(data)

f = SuperFile("log.txt","w+")       
process = subprocess.Popen(command, stdout=f, stderr=f)

এটি কাজ করবে না: সাবপ্রসেস মডিউলটি কাঁটাচামচ করে দেয় এবং stdoutপাস করা ফাইল অবজেক্টের ফাইল বিবরণীতে ফাইল বর্ণনাকারী সেট করে । লিখন পদ্ধতিটি কখনই ডাকা হত না (স্ট্ডারদের জন্য অন্ততপক্ষে যা প্রসপ্রেসেস করে তা আমি অনুমান করি যে এটি স্টাডাউটের ক্ষেত্রে একই)।
t.animal

2

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

import subprocess
import sys
import os
import select
# returns command exit status, stdout text, stderr text
# rtoutput: show realtime output while running
def run_script(cmd,rtoutput=0):
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    poller = select.poll()
    poller.register(p.stdout, select.POLLIN)
    poller.register(p.stderr, select.POLLIN)

    coutput=''
    cerror=''
    fdhup={}
    fdhup[p.stdout.fileno()]=0
    fdhup[p.stderr.fileno()]=0
    while sum(fdhup.values()) < len(fdhup):
        try:
            r = poller.poll(1)
        except select.error, err:
            if err.args[0] != EINTR:
                raise
            r=[]
        for fd, flags in r:
            if flags & (select.POLLIN | select.POLLPRI):
                c = os.read(fd, 1024)
                if rtoutput:
                    sys.stdout.write(c)
                    sys.stdout.flush()
                if fd == p.stderr.fileno():
                    cerror+=c
                else:
                    coutput+=c
            else:
                fdhup[fd]=1
    return p.poll(), coutput.strip(), cerror.strip()

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

2

পূর্ববর্তী উত্তরের মতোই তবে নীচের সমাধানটি উইন্ডোজটিতে রিয়েলটাইম মুদ্রণ এবং লগ ইন করার জন্য একটি সাধারণ পদ্ধতি সরবরাহ করার জন্য ( রিয়েলটাইম-আউটপুট-ব্যবহার-পাইথন পেয়ে ) ব্যবহার করার জন্য উইন্ডোজে কাজ করেছিল :

def print_and_log(command, logFile):
    with open(logFile, 'wb') as f:
        command = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)

        while True:
            output = command.stdout.readline()
            if not output and command.poll() is not None:
                f.close()
                break
            if output:
                f.write(output)
                print(str(output.strip(), 'utf-8'), flush=True)
        return command.poll()

2

আমি মনে করি যে subprocess.communicateপদ্ধতিটি কিছুটা বিভ্রান্তিকর: এটি আসলে আপনি যে স্টাডআউট এবং স্টাডারকে নির্দিষ্ট করেছেন তা পূরণ করে subprocess.Popen

তবুও, থেকে পড়া subprocess.PIPEআপনাকে প্রদান করতে পারে subprocess.Popen'র stdout- এ এবং দ্বারা stderr পরামিতি অবশেষে ওএস নল বাফার ভরাট এবং আপনার অ্যাপ্লিকেশন অচলাবস্থা পাবেন (বিশেষ করে যদি আপনি একাধিক প্রসেস / থ্রেড যে ব্যবহার করা আবশ্যক করেছি subprocess)।

আমার প্রস্তাবিত সমাধানটি হল স্টডআউট এবং স্টডারকে ফাইলগুলি সরবরাহ করা - এবং ডেডলকিং থেকে পড়ার পরিবর্তে ফাইলগুলির বিষয়বস্তু পড়ুন PIPE। এই ফাইলগুলি হতে পারে tempfile.NamedTemporaryFile()- যা লিখিত হওয়ার সময়েও পড়ার জন্য অ্যাক্সেস করা যেতে পারে subprocess.communicate

নীচে একটি নমুনা ব্যবহার:

        try:
            with ProcessRunner(('python', 'task.py'), env=os.environ.copy(), seconds_to_wait=0.01) as process_runner:
                for out in process_runner:
                    print(out)
        catch ProcessError as e:
            print(e.error_message)
            raise

এবং এটি হ'ল সোর্স কোড যা এটি যা করে তা ব্যাখ্যা করার জন্য আমি যতটা কমেন্টের সাথে ব্যবহার করতে প্রস্তুত :

আপনি যদি পাইথন 2 ব্যবহার করে থাকেন তবে দয়া করে প্রথমে পাইপি থেকে সাবপ্রসেস 32 প্যাকেজের সর্বশেষতম সংস্করণটি ইনস্টল করার বিষয়টি নিশ্চিত করুন ।


import os
import sys
import threading
import time
import tempfile
import logging

if os.name == 'posix' and sys.version_info[0] < 3:
    # Support python 2
    import subprocess32 as subprocess
else:
    # Get latest and greatest from python 3
    import subprocess

logger = logging.getLogger(__name__)


class ProcessError(Exception):
    """Base exception for errors related to running the process"""


class ProcessTimeout(ProcessError):
    """Error that will be raised when the process execution will exceed a timeout"""


class ProcessRunner(object):
    def __init__(self, args, env=None, timeout=None, bufsize=-1, seconds_to_wait=0.25, **kwargs):
        """
        Constructor facade to subprocess.Popen that receives parameters which are more specifically required for the
        Process Runner. This is a class that should be used as a context manager - and that provides an iterator
        for reading captured output from subprocess.communicate in near realtime.

        Example usage:


        try:
            with ProcessRunner(('python', task_file_path), env=os.environ.copy(), seconds_to_wait=0.01) as process_runner:
                for out in process_runner:
                    print(out)
        catch ProcessError as e:
            print(e.error_message)
            raise

        :param args: same as subprocess.Popen
        :param env: same as subprocess.Popen
        :param timeout: same as subprocess.communicate
        :param bufsize: same as subprocess.Popen
        :param seconds_to_wait: time to wait between each readline from the temporary file
        :param kwargs: same as subprocess.Popen
        """
        self._seconds_to_wait = seconds_to_wait
        self._process_has_timed_out = False
        self._timeout = timeout
        self._process_done = False
        self._std_file_handle = tempfile.NamedTemporaryFile()
        self._process = subprocess.Popen(args, env=env, bufsize=bufsize,
                                         stdout=self._std_file_handle, stderr=self._std_file_handle, **kwargs)
        self._thread = threading.Thread(target=self._run_process)
        self._thread.daemon = True

    def __enter__(self):
        self._thread.start()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self._thread.join()
        self._std_file_handle.close()

    def __iter__(self):
        # read all output from stdout file that subprocess.communicate fills
        with open(self._std_file_handle.name, 'r') as stdout:
            # while process is alive, keep reading data
            while not self._process_done:
                out = stdout.readline()
                out_without_trailing_whitespaces = out.rstrip()
                if out_without_trailing_whitespaces:
                    # yield stdout data without trailing \n
                    yield out_without_trailing_whitespaces
                else:
                    # if there is nothing to read, then please wait a tiny little bit
                    time.sleep(self._seconds_to_wait)

            # this is a hack: terraform seems to write to buffer after process has finished
            out = stdout.read()
            if out:
                yield out

        if self._process_has_timed_out:
            raise ProcessTimeout('Process has timed out')

        if self._process.returncode != 0:
            raise ProcessError('Process has failed')

    def _run_process(self):
        try:
            # Start gathering information (stdout and stderr) from the opened process
            self._process.communicate(timeout=self._timeout)
            # Graceful termination of the opened process
            self._process.terminate()
        except subprocess.TimeoutExpired:
            self._process_has_timed_out = True
            # Force termination of the opened process
            self._process.kill()

        self._process_done = True

    @property
    def return_code(self):
        return self._process.returncode



1

এখানে আমি আমার প্রকল্পগুলির একটিতে ব্যবহার করছি যা একটি বর্গ। এটি লগটিতে একটি সাবপ্রসেসের আউটপুট পুনঃনির্দেশ করে। প্রথমে আমি কেবল লেখার পদ্ধতিটি মুছে ফেলার চেষ্টা করেছি তবে এটি কাজ করে না কারণ সাবপ্রসেসি কখনই এটি কল করে না (ফাইলটিস্ক্রিপ্টরের স্তরে পুনর্নির্দেশ ঘটে)। সুতরাং আমি আমার নিজস্ব পাইপ ব্যবহার করছি, এটি সাব-প্রসেস-মডিউলটিতে কীভাবে করা হয়েছে তার সমান। অ্যাডাপ্টারে সমস্ত লগিং / প্রিন্টিং লজিককে আবদ্ধ করার সুবিধা রয়েছে এবং আপনি কেবল লগারের উদাহরণগুলি এখানে পাস করতে পারেন Popen:subprocess.Popen("/path/to/binary", stderr = LogAdapter("foo"))

class LogAdapter(threading.Thread):

    def __init__(self, logname, level = logging.INFO):
        super().__init__()
        self.log = logging.getLogger(logname)
        self.readpipe, self.writepipe = os.pipe()

        logFunctions = {
            logging.DEBUG: self.log.debug,
            logging.INFO: self.log.info,
            logging.WARN: self.log.warn,
            logging.ERROR: self.log.warn,
        }

        try:
            self.logFunction = logFunctions[level]
        except KeyError:
            self.logFunction = self.log.info

    def fileno(self):
        #when fileno is called this indicates the subprocess is about to fork => start thread
        self.start()
        return self.writepipe

    def finished(self):
       """If the write-filedescriptor is not closed this thread will
       prevent the whole program from exiting. You can use this method
       to clean up after the subprocess has terminated."""
       os.close(self.writepipe)

    def run(self):
        inputFile = os.fdopen(self.readpipe)

        while True:
            line = inputFile.readline()

            if len(line) == 0:
                #no new data was added
                break

            self.logFunction(line.strip())

আপনার যদি লগিংয়ের প্রয়োজন না হয় তবে কেবল ব্যবহার print()করতে চান তবে আপনি অবশ্যই কোডের বড় অংশগুলি সরাতে এবং শ্রেণিটি আরও ছোট রাখতে পারেন। এছাড়াও আপনি একটি দ্বারা এটি প্রসারিত করতে পারে __enter__এবং __exit__পদ্ধতি এবং কল finishedমধ্যে __exit__আপনি সহজেই প্রসঙ্গ হিসাবে এটি ব্যবহার করতে পারে তাই।


1

পাইথোনিক সমাধানগুলির কোনওোটাই আমার পক্ষে কাজ করেনি। দেখা গেল যে proc.stdout.read()বা এর মতোই চিরকালের জন্য অবরুদ্ধ হতে পারে।

অতএব, আমি এটি ব্যবহার করি tee:

subprocess.run('./my_long_running_binary 2>&1 | tee -a my_log_file.txt && exit ${PIPESTATUS}', shell=True, check=True, executable='/bin/bash')

আপনি যদি ইতিমধ্যে ব্যবহার করে থাকেন তবে এই সমাধানটি সুবিধাজনক shell=True

${PIPESTATUS}সম্পূর্ণ কমান্ড চেইনের সাফল্যের স্থিতি অর্জন করে (কেবলমাত্র ব্যাশে উপলব্ধ)। যদি আমি বাদ না দিয়ে থাকি && exit ${PIPESTATUS}তবে এটি সর্বদা শূন্য হয় যেহেতু teeকখনই ব্যর্থ হয় না।

unbuffer"পাইপ বাফার "টি পূরণ না হওয়া অবধি দীর্ঘ পথ অপেক্ষা না করে প্রতিটি লাইনের সাথে সাথে টার্মিনালে মুদ্রণের জন্য প্রয়োজনীয় হতে পারে। যাইহোক, আনফফার দৃ SIG়তার (প্রস্থান) জন্য প্রস্থান স্থিতি গ্রাস করে ...

2>&1 ফাইলে stderror লগ করে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.