तुरंत फाइल करने के लिए पायथन स्टडआउट लिखें


51

जब पायथन स्क्रिप्ट से टेक्स्ट फाइल ( python script.py > log) में स्टडआउट लिखने की कोशिश की जाती है , तो कमांड शुरू होने पर टेक्स्ट फाइल बनाई जाती है, लेकिन पायथन स्क्रिप्ट के खत्म होने तक वास्तविक कंटेंट नहीं लिखा जाता है। उदाहरण के लिए:

script.py:

import time
for i in range(10):
    print('bla')
    time.sleep(5)

जब कॉल किया जाता है तो हर 5 सेकंड में प्रिंट करने के लिए प्रिंट करता है python script.py, लेकिन जब मैं कॉल करता हूं python script.py > log, तो स्क्रिप्ट खत्म होने तक लॉग फ़ाइल का आकार शून्य रहता है। क्या लॉग फ़ाइल में सीधे लिखना संभव है, जैसे कि आप स्क्रिप्ट की प्रगति का अनुसरण कर सकते हैं (उदाहरण के लिए tail)?

संपादित करें यह पता चला है कि python -u script.pyचाल है, मैं stdout के बफरिंग के बारे में पता नहीं था।


1
@ जेज्मेक, मैं प्रश्न को गलत समझ सकता था।
१२:२१

जवाबों:


64

ऐसा इसलिए हो रहा है क्योंकि आम तौर पर जब प्रक्रिया STDOUT को टर्मिनल के अलावा किसी अन्य चीज़ पर पुनर्निर्देशित किया जाता है, तो आउटपुट को कुछ OS-विशिष्ट-आकार के बफर (शायद कई मामलों में 4k या 8k) में बफ़र किया जाता है। इसके विपरीत, जब टर्मिनल पर आउटपुट किया जाता है, तो STDOUT लाइन-बफ़र्ड होगा या बफ़र नहीं किया जाएगा, इसलिए आपको \nप्रत्येक वर्ण के बाद या प्रत्येक वर्ण के लिए आउटपुट दिखाई देगा ।

आप आम तौर पर stdbufउपयोगिता के साथ बफरिंग को बदल सकते हैं :

stdbuf -oL python script.py > log

अब यदि आप tail -F log, आपको प्रत्येक पंक्ति आउटपुट को उत्पन्न होते ही देखना चाहिए।


प्रत्येक प्रिंट के बाद समान रूप से आउटपुट स्ट्रीम के वैकल्पिक रूप से स्पष्ट फ्लशिंग होना चाहिए। ऐसा लगता है कि sys.stdout.flush()पायथन में इसे हासिल करना चाहिए। यदि आप पायथन 3.3 या नए का उपयोग कर रहे हैं, तो printफ़ंक्शन में एक flushकीवर्ड भी है जो ऐसा करता है print('hello', flush=True):।


8
धन्यवाद, मैं बफरिंग के बारे में नहीं जानता था! यह जानकर, Google ने मुझे जल्दी से बताया कि python -u script.pyयह चाल है। संपादित करें एक साथ इतने सारे उत्तर, मैंने आपका स्वीकार कर लिया क्योंकि इसने मुझे बफरिंग की दिशा में इशारा किया।
बार्ट

1
@ जुलब्रा कूल, हां मुझे नहीं पता था कि अजगर के पास वह विकल्प भी था। कुछ कमांड-लाइन कार्यक्रमों में भी समान विकल्प होते हैं - उदाहरण के --line-bufferedलिए grep, लेकिन कुछ अन्य नहीं। stdbufसामान्य कैटचेल उपयोगिता उन लोगों से निपटने के लिए है जो नहीं करते हैं।
डिजिटल ट्रामा

@ डिगटलट्रूमा: क्या stdbuf -o0 python script.py > logइस तरह की निर्धारित परिस्थितियों में किसी भी बफरिंग का उपयोग करना बेहतर नहीं है?
heemayl

@heemayl -oLएक समझौता है। सामान्य रूप से बड़े बफ़र कहीं बेहतर प्रदर्शन प्रदान करेंगे जब कहीं पुनर्निर्देशित किया जाएगा (कम सिस्टम कॉल और कम आई / ओ संचालन)। हालाँकि यदि यह प्रत्येक वर्ण को देखना आवश्यक है क्योंकि यह आउटपुट है तो हाँ, -o0आवश्यक होगा।
डिजिटल ट्रॉमा

@Paul कृपया उत्तर के बीच कॉपी पेस्ट सामग्री से बचें, या कम से कम उन मूल लेखकों का उल्लेख करें जो सामग्री प्रदान करते हैं।
बकुरीउ

44

यह काम करना चाहिए:

import time, sys
for i in range(10):
    print('bla')
    sys.stdout.flush()
    time.sleep(5)

जैसा कि पायथन stdoutडिफ़ॉल्ट रूप से बफर करेगा , यहां मैंने sys.stdout.flush()बफर को फ्लश करने के लिए उपयोग किया है।

एक और समाधान होगा -u(अनफ़िल्टर्ड) स्विच का उपयोग करना python। तो, निम्नलिखित भी करेंगे:

python -u script.py >> log

11

अनियंत्रित आउटपुट के लिए अजगर के अपने विकल्प का उपयोग करने के विषय पर विविधता #!/usr/bin/python -uपहली पंक्ति के रूप में उपयोग करना होगा ।

साथ #!/usr/bin/env pythonकाम है कि अतिरिक्त तर्क वाला नहीं है, तो वैकल्पिक रूप से, एक चला सकते हैं PYTHONUNBUFFERED=1 ./my_scriipt.py > output.txtया दो चरणों में कर:

$ export PYTHONUNBUFFERED=1
$ ./myscript.py

10

आप पास करना चाहिए flush=Trueकरने के लिए printसमारोह:

import time

for i in range(10):
    print('bla', flush=True)
    time.sleep(5)

प्रलेखन के अनुसार, डिफ़ॉल्ट रूप से, printनिस्तब्धता के बारे में कुछ भी लागू नहीं करता है:

चाहे आउटपुट बफ़र किया जाता है, आमतौर पर फ़ाइल द्वारा निर्धारित किया जाता है, लेकिन यदि flushकीवर्ड तर्क सही है, तो स्ट्रीम जबरन फ़्लश की जाती है।

और दस्तावेज़ के sysस्ट्रेम्स कहते हैं:

जब इंटरेक्टिव, मानक धाराएँ लाइन-बफ़र्ड होती हैं। अन्यथा, वे नियमित पाठ फ़ाइलों की तरह ब्लॉक-बफर्ड हैं। आप -uकमांड-लाइन विकल्प के साथ इस मान को ओवरराइड कर सकते हैं ।


यदि आप अजगर के एक प्राचीन संस्करण के साथ फंस गए हैं, तो आपको धारा की flushविधि को कॉल करना होगा sys.stdout:

import sys
import time

for i in range(10):
    print('bla')
    sys.stdout.flush()
    time.sleep(5)

1
फ्लश = सच्चा तर्क पायथन 3.4.2 के साथ अच्छी तरह से काम करता है, वास्तव में प्राचीन के साथ काम नहीं करता है (..) पायथन 2.7.9
बार्ट

यह उत्तर वही बताता है जो DigitalTrauma10 घंटे पहले कहा गया था। आपको उसका पद फिर से बढ़ाना चाहिए, फिर से वही बात पोस्ट नहीं करनी चाहिए।
12

4
@dotancohen वास्तव में तीसरे पक्ष के लेखक द्वारा खान के बादprint(flush=True) उस उत्तर के बारे में हिस्सा जोड़ा गया था । मैं अपने जवाब से सामग्री को चीरने के लिए उन्हें बिना किसी क्रेडिट के डालने का बुरा स्वाद पाता हूं। मैंने अपना उत्तर पूरी तरह से जोड़ने का फैसला किया क्योंकि कोई भी उत्तर प्राप्त करने के सबसे सरल तरीके का कोई उल्लेख नहीं दिया गया था, जो ओपी को अजगर के नए संस्करणों में चाहिए था, और मैंने पूर्णता के लिए "पुराने तरीके" को जोड़ा। अगली बार टिप्पणी करने से पहले और संशोधन करने से पहले कृपया संशोधन इतिहास देखें।
बाकूरी

@ बकुरीउ: मुझे क्षमा करें! यह हमेशा एक कारण बताता है कि जब डाउनवोटिंग क्यों होता है । क्या आप कृपया पोस्ट को थोड़ा संपादित कर सकते हैं ताकि मैं अपने डाउनवोट को अपवोट में बदल सकूं? धन्यवाद!
dotancohen

यदि आप __future__आयात करते हैं तो इसे पायथन 2.7 के साथ काम करना चाहिए from __future__ import print_function:। लेकिन हाँ, यह केवल पायथन 3 के साथ संगतता के लिए है
सर्जियो कोलोडियाज़नी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.