अजगर का उपयोग करके फ़ाइल में 'प्रिंट' आउटपुट को पुनर्निर्देशित कैसे करें?


184

मैं अजगर का उपयोग करके एक .txt फ़ाइल में प्रिंट को पुनर्निर्देशित करना चाहता हूं। मेरे पास 'लूप' के लिए है, जो कि मेरे प्रत्येक .bam फ़ाइल के आउटपुट को 'प्रिंट' करेगा, जबकि मैं इन सभी आउटपुट को एक फ़ाइल पर पुनर्निर्देशित करना चाहता हूं। इसलिए मैंने डालने की कोशिश की

 f = open('output.txt','w'); sys.stdout = f

मेरी स्क्रिप्ट की शुरुआत में। हालाँकि मुझे .txt फाइल में कुछ नहीं मिलता है। मेरी स्क्रिप्ट है:

#!/usr/bin/python

import os,sys
import subprocess
import glob
from os import path

f = open('output.txt','w')
sys.stdout = f

path= '/home/xug/nearline/bamfiles'
bamfiles = glob.glob(path + '/*.bam')

for bamfile in bamfiles:
    filename = bamfile.split('/')[-1]
    print 'Filename:', filename
    samtoolsin = subprocess.Popen(["/share/bin/samtools/samtools","view",bamfile],
                                  stdout=subprocess.PIPE,bufsize=1)
    linelist= samtoolsin.stdout.readlines()
    print 'Readlines finished!'
    ........print....
    ........print....

तो समस्या क्या है? इस sys.stdout के अलावा कोई और तरीका?

मुझे अपना परिणाम देखने की आवश्यकता है:

Filename: ERR001268.bam
Readlines finished!
Mean: 233
SD: 10
Interval is: (213, 252)

7
उपयोग क्यों नहीं f.write(data)?
एरान ज़िमरमैन गॉनन

हाँ, लेकिन मेरे पास प्रत्येक bam फ़ाइल (मतलब, SD, अंतराल ...) के लिए कई डेटा हैं, मैं इन डेटा को एक-एक करके कैसे डाल सकता हूं?
देखो

f.write(line)- यह अंत में एक लाइन ब्रेक सम्मिलित करता है।
एरन ज़िमरमैन गॉनन

8
@ ईरान ज़िमरमैन: f.write(line)डेटा में एक लाइन ब्रेक नहीं जोड़ता है।
हुग्डब्रोर्न

तुम सही हो, मेरा बुरा। हमेशा की तरह f.write(line+'\n'), लेकिन ..
एरन ज़िमरमैन गॉनन

जवाबों:


274

ऐसा करने का सबसे स्पष्ट तरीका फ़ाइल ऑब्जेक्ट पर प्रिंट करना होगा:

with open('out.txt', 'w') as f:
    print >> f, 'Filename:', filename     # Python 2.x
    print('Filename:', filename, file=f)  # Python 3.x

हालाँकि, पुनर्निर्देशन stdout भी मेरे लिए काम करता है। यह इस तरह से एक-बंद स्क्रिप्ट के लिए शायद ठीक है:

import sys

orig_stdout = sys.stdout
f = open('out.txt', 'w')
sys.stdout = f

for i in range(2):
    print 'i = ', i

sys.stdout = orig_stdout
f.close()

शेल से बाहरी रूप से पुनर्निर्देशित करना एक और अच्छा विकल्प है:

./script.py > out.txt

अन्य सवाल:

आपकी स्क्रिप्ट में पहला फ़ाइल नाम क्या है? मैं इसे आरंभीकृत नहीं देखता।

मेरा पहला अनुमान है कि ग्लोब को कोई बामफाइल्स नहीं मिलता है, और इसलिए लूप नहीं चलता है। जाँचें कि फ़ोल्डर मौजूद है, और अपनी स्क्रिप्ट में बामफाइल्स प्रिंट करें।

इसके अलावा, रास्ते और फ़ाइल नाम में हेरफेर करने के लिए os.path.join और os.path.basename का उपयोग करें ।


आपके कोड की पंक्ति 8 फ़ाइल नाम के एक चर का उपयोग करती है, लेकिन इसे अभी तक नहीं बनाया गया है। बाद में लूप में आप इसे फिर से उपयोग करते हैं, लेकिन प्रासंगिक नहीं।
ग्रिंगो सुवे

2
यदि आपको ज़रूरत नहीं है तो sys.stdout को बदलने के लिए बुरा अभ्यास।
मशीन तड़के

3
@ मैं इस तरह एक साधारण स्क्रिप्ट के लिए बुरा है आश्वस्त नहीं हूँ।
ग्रिंगो सुवे

4
+1 Haha अच्छी तरह से आप मेरा उत्थान कर सकते हैं क्योंकि यह सही तरीका है यदि आप इसे बिल्कुल गलत तरीके से करते हैं तो करना चाहिए ... लेकिन मैं अभी भी कहता हूं कि आपको इसे नियमित फ़ाइल आउटपुट के साथ करना चाहिए।
मशीन तड़के

1
कंसोल पर आउटपुट को रीडायरेक्ट और प्रिंट कैसे करें? लगता है कि जब प्रिंट को पुनर्निर्देशित किया गया है तो पायथन में "प्रिंट ()" नहीं दिखाया जा सकता है?
निर्गमन

70

आप >>ऑपरेटर के साथ प्रिंट को रीडायरेक्ट कर सकते हैं ।

f = open(filename,'w')
print >>f, 'whatever'     # Python 2.x
print('whatever', file=f) # Python 3.x

ज्यादातर मामलों में, आप फ़ाइल को सामान्य रूप से लिखना बेहतर समझते हैं।

f.write('whatever')

या, यदि आपके पास कई आइटम हैं जिन्हें आप रिक्त स्थान के साथ लिखना चाहते हैं, जैसे print:

f.write(' '.join(('whatever', str(var2), 'etc')))

2
यदि बहुत सारे आउटपुट स्टेटमेंट हैं तो ये जल्दी बूढ़े हो सकते हैं। पोस्टर मूल विचार मान्य है; स्क्रिप्ट में कुछ और गड़बड़ है।
ग्रिंगो सुवे

1
पोस्टर का मूल विचार बिल्कुल अमान्य है। यहां कोई स्टडीआउट पुनर्निर्देशित करने का कोई कारण नहीं है, क्योंकि वह पहले से ही एक चर में डेटा प्राप्त करता है।
मशीन तड़के

मुझे लगता है कि उनका मतलब "तकनीकी रूप से मान्य" था, जिसमें आप कर सकते हैं, वास्तव में, पुनर्निर्देशित sys.stdout, यह नहीं कि यह एक अच्छा विचार था।
23

35

पायथन 2 या पायथन 3 एपीआई संदर्भ:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

फ़ाइल तर्क एक के साथ एक वस्तु होना चाहिए write(string)विधि; यदि यह मौजूद नहीं है या None, sys.stdoutइसका उपयोग किया जाएगा। चूंकि मुद्रित तर्क टेक्स्ट स्ट्रिंग्स में परिवर्तित होते हैं, इसलिए print()बाइनरी मोड फ़ाइल ऑब्जेक्ट के साथ उपयोग नहीं किया जा सकता है। इन के लिए, file.write(...)बजाय का उपयोग करें ।

चूँकि फ़ाइल ऑब्जेक्ट में आम तौर पर write()विधि होती है, आपको बस एक फ़ाइल ऑब्जेक्ट को उसके तर्क में पास करना है ।

फ़ाइल में लिखें / ओवरराइट करें

with open('file.txt', 'w') as f:
    print('hello world', file=f)

फ़ाइल में लिखें / संलग्न करें

with open('file.txt', 'a') as f:
    print('hello world', file=f)

2
मैं बस उलझन में था कि क्यों उन पहले के कुछ जवाबों ने बंदर को वैश्विक रूप दिया था sys.stdout:(
यो

35

यह पूरी तरह से काम करता है:

import sys
sys.stdout=open("test.txt","w")
print ("hello")
sys.stdout.close()

अब हैलो को test.txt फाइल में लिखा जाएगा। stdoutएक के साथ बंद करना सुनिश्चित करें close, इसके बिना सामग्री को फ़ाइल में सहेजा नहीं जाएगा


3
लेकिन भले ही हम प्रदर्शन करते हैं sys.stdout.close(), अगर आप अजगर खोल में कुछ भी टाइप करते हैं तो यह ValueError: I/O operation on closed file. imgur.com/a/xby9P के रूप में त्रुटि दिखाएगा । इसे संभालने का सबसे अच्छा तरीका यह है कि @Gringo Suave ने क्या पोस्ट किया है
Mourya

24

उपयोग न करें print, उपयोग करेंlogging

आप sys.stdoutकिसी फ़ाइल को इंगित करने के लिए बदल सकते हैं , लेकिन इस समस्या को संभालने के लिए यह एक बहुत ही क्लूनी और अनम्य तरीका है। उपयोग करने के बजाय print, loggingमॉड्यूल का उपयोग करें ।

इसके साथ logging, आप अपनी इच्छानुसार प्रिंट कर सकते हैं stdoutया आउटपुट को किसी फ़ाइल में भी लिख सकते हैं। तुम भी अलग अलग संदेश के स्तर का उपयोग करें (कर सकते हैं critical, error, warning, info, debug), उदाहरण के लिए, केवल प्रमुख मुद्दों कंसोल के लिए मुद्रित करने के लिए, लेकिन अभी भी एक फाइल करने के लिए नाबालिग कोड कार्यों लॉग इन करें।

एक सरल उदाहरण

आयात करें logging, loggerप्रसंस्करण स्तर प्राप्त करें और सेट करें:

import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG) # process everything, even if everything isn't printed

यदि आप stdout में प्रिंट करना चाहते हैं:

ch = logging.StreamHandler()
ch.setLevel(logging.INFO) # or any other level
logger.addHandler(ch)

यदि आप किसी फ़ाइल पर लिखना चाहते हैं (यदि आप केवल फ़ाइल को लिखना चाहते हैं तो अंतिम अनुभाग छोड़ें):

fh = logging.FileHandler('myLog.log')
fh.setLevel(logging.DEBUG) # or any level you want
logger.addHandler(fh)

फिर, जहाँ भी आप किसी printएक loggerविधि का उपयोग करेंगे :

# print(foo)
logger.debug(foo)

# print('finishing processing')
logger.info('finishing processing')

# print('Something may be wrong')
logger.warning('Something may be wrong')

# print('Something is going really bad')
logger.error('Something is going really bad')

अधिक उन्नत loggingसुविधाओं का उपयोग करने के बारे में अधिक जानने के लिए , loggingपायथन डॉक्स में उत्कृष्ट ट्यूटोरियल पढ़ें ।


नमस्ते, मैं इस लॉगिंग का उपयोग कंसोल डेटा लिखने के लिए लॉग फ़ाइल में उस समय के साथ करना चाहता हूं जिस समय उस डेटा को लिया जाता है। लेकिन मैं लॉगिंग फ़ंक्शन या लाइब्रेरी को ठीक से समझने में सक्षम नहीं हूं। क्या आप मुझे इस के साथ मदद कर सकते हैं
हारिस

@haris पायथन डॉक्स लॉगिंग ट्यूटोरियल के माध्यम से पढ़ें और स्टैक ओवरफ्लो पर अन्य प्रश्नों में उदाहरण देखें (उनमें से बहुत सारे हैं)। यदि आप अभी भी इसे प्राप्त करने में असमर्थ हैं, तो एक नया प्रश्न पूछें।
जफाम

12

सबसे आसान समाधान अजगर के माध्यम से नहीं है; खोल के माध्यम से। आपकी फ़ाइल की पहली पंक्ति से ( #!/usr/bin/python) मैं अनुमान लगा रहा हूँ कि आप UNIX सिस्टम पर हैं। printजैसे आप सामान्य रूप से कथन का उपयोग करेंगे, और फ़ाइल को अपनी स्क्रिप्ट में बिल्कुल भी न खोलें। जब आप फ़ाइल चलाने के लिए जाते हैं, इसके बजाय

./script.py

फ़ाइल चलाने के लिए, का उपयोग करें

./script.py > <filename>

जहाँ आप <filename>उस फ़ाइल के नाम से प्रतिस्थापित करते हैं जिसे आप आउटपुट में जाना चाहते हैं। >टोकन टोकन का पालन करते हुए वर्णित फाइल करने के लिए (सबसे) सेट stdout में गोले बताता है।

यहां एक महत्वपूर्ण बात जिसका उल्लेख करना आवश्यक है, वह यह है कि "script.py" ./script.pyको चलाने के लिए निष्पादन योग्य बनाने की आवश्यकता है ।

इसलिए दौड़ने से पहले ./script.pyइस कमांड को निष्पादित करें

chmod a+x script.py (सभी उपयोगकर्ताओं के लिए स्क्रिप्ट को निष्पादन योग्य बनाएं)


3
./script.py> <filename> 2> & 1 आपको stderr को भी कैप्चर करना होगा। 2> और 1 को वह कर देगा
rtaft

1
@ क्यों प्रश्न विशेष रूप printसे एक फ़ाइल के आउटपुट को पाइप करना चाहता है । टर्मिनल पर प्रिंट करने के लिए स्टडआउट (स्टैक के निशान और इस तरह) की अपेक्षा करना उचित होगा।
एरोन डफोर

उन्होंने कहा कि यह काम नहीं कर रहा था, मेरा काम भी नहीं कर रहा था। मुझे बाद में पता चला कि मैं जिस ऐप पर काम कर रहा था, वह सब कुछ stderr ... idk क्यों निर्देशित करने के लिए कॉन्फ़िगर किया गया था।
13 सितंबर को रात

5

यदि आप लिनक्स का उपयोग कर रहे हैं, तो मेरा सुझाव है कि आप teeकमांड का उपयोग करें । कार्यान्वयन इस प्रकार है:

python python_file.py | tee any_file_name.txt

यदि आप कोड में कुछ भी नहीं बदलना चाहते हैं, तो मुझे लगता है कि यह सबसे अच्छा संभव समाधान हो सकता है। आप लकड़हारे को भी लागू कर सकते हैं लेकिन आपको कोड में कुछ बदलाव करने की आवश्यकता है।


1
महान; इसके लिए देख रहा था
विक्रोबोट

4

आपको यह उत्तर पसंद नहीं आ सकता है, लेकिन मुझे लगता है कि यह सही है। जब तक यह पूरी तरह से आवश्यक नहीं है, तब तक अपने स्टडआउट गंतव्य को न बदलें (हो सकता है कि आप एक पुस्तकालय का उपयोग कर रहे हैं जो केवल स्टडआउट के लिए आउटपुट करता है ??? स्पष्ट रूप से यहां मामला नहीं है)।

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

यहाँ एक उदाहरण है:

out_lines = []
for bamfile in bamfiles:
    filename = bamfile.split('/')[-1]
    out_lines.append('Filename: %s' % filename)
    samtoolsin = subprocess.Popen(["/share/bin/samtools/samtools","view",bamfile],
                                  stdout=subprocess.PIPE,bufsize=1)
    linelist= samtoolsin.stdout.readlines()
    print 'Readlines finished!'
    out_lines.extend(linelist)
    out_lines.append('\n')

और फिर जब आप सभी अपनी "डेटा लाइनों" को एक लाइन प्रति सूची आइटम एकत्र करने के लिए कर रहे हैं, तो आप उन्हें कुछ '\n'पात्रों के साथ जोड़कर पूरी चीज को आउटपुट योग्य बना सकते हैं; हो सकता है कि withअतिरिक्त सुरक्षा के लिए भी आप अपने आउटपुट स्टेटमेंट को ब्लॉक में लपेटें (स्वचालित रूप से आपका आउटपुट हैंडल बंद हो जाएगा, भले ही कुछ गलत हो)

out_string = '\n'.join(out_lines)
out_filename = 'myfile.txt'
with open(out_filename, 'w') as outf:
    outf.write(out_string)
print "YAY MY STDOUT IS UNTAINTED!!!"

लेकिन यदि आप लिखने के लिए डेटा के बहुत सारे है, तो आप कर सकता है यह एक समय में एक टुकड़ा लिखें। मुझे नहीं लगता कि यह आपके आवेदन के लिए प्रासंगिक है लेकिन यहां विकल्प है:

out_filename = 'myfile.txt'
outf = open(out_filename, 'w')
for bamfile in bamfiles:
    filename = bamfile.split('/')[-1]
    outf.write('Filename: %s' % filename)
    samtoolsin = subprocess.Popen(["/share/bin/samtools/samtools","view",bamfile],
                                  stdout=subprocess.PIPE,bufsize=1)
    mydata = samtoolsin.stdout.read()
    outf.write(mydata)
outf.close()

1
मूल के डिस्क कैशिंग प्रदर्शन के साथ स्वीकार्य होना चाहिए। हालाँकि इस समाधान में बहुत अधिक आउटपुट होने पर मेमोरी आवश्यकताओं को गुब्बारा करने का दोष है। हालांकि शायद यहाँ चिंता करने की कोई बात नहीं है, फिर भी यदि संभव हो तो इससे बचना एक अच्छा विचार है। रेंज के बजाय xrange (py3 रेंज) का उपयोग करने के रूप में एक ही विचार, आदि
ग्रिंगो Suave

@Gringo: उन्होंने इस आवश्यकता को निर्दिष्ट नहीं किया। शायद ही कभी मैं किसी फ़ाइल के लिए पर्याप्त डेटा लिखता हूं कि यह प्रासंगिक होगा। यह xrange के समान विचार नहीं है क्योंकि xrange फ़ाइल i / o के साथ सौदा नहीं करता है। डिस्क कैशिंग मदद कर सकता है लेकिन कोड के एक बड़े निकाय के लिए फ़ाइल हैंडल को खुले रखना अभी भी एक बुरा अभ्यास है।
मशीन तड़के

1
आपकी टिप्पणी स्वयं विरोधाभासी है। ईमानदार होने के लिए दोनों दृष्टिकोणों का प्रदर्शन पहलू गैर-भारी मात्रा में डेटा के लिए अप्रासंगिक है। xrange निश्चित रूप से समान है, यह एक बार में एक मेमोरी में सभी के बजाय एक टुकड़े पर काम करता है। शायद एक जनरेटर बनाम सूची हालांकि एक बेहतर उदाहरण है।
ग्रिंगो सुवे

@Gringo: मैं यह देखने में विफल हूं कि मेरी टिप्पणी अपने आप में कैसे विरोधाभासी है। हो सकता है कि प्रदर्शन का पहलू प्रासंगिक न हो, विस्तारित अवधि के लिए फ़ाइल हैंडल को खुला रखना हमेशा त्रुटि के जोखिम को बढ़ाता है। प्रोग्रामिंग फ़ाइल में i / o हमेशा अपने स्वयं के प्रोग्राम के भीतर कुछ करने की तुलना में अधिक जोखिम भरा होता है, क्योंकि इसका मतलब है कि आपको ओएस के माध्यम से बाहर पहुंचना होगा और फ़ाइल लॉक के साथ गड़बड़ करना होगा। आपके पास जितनी छोटी फ़ाइल खुलेगी, उतनी ही बेहतर, क्योंकि आप अपने कोड से फ़ाइल सिस्टम को नियंत्रित नहीं करते हैं। xrange अलग है क्योंकि इसका फ़ाइल i / o से कोई लेना देना नहीं है, और FYI करें मैं शायद ही कभी xrange का उपयोग करता हूं; चीयर्स
मशीन तड़के

2
@Gringo: मैं आपकी आलोचना की सराहना करता हूं और गर्म बहस का आनंद लिया। यद्यपि हम कुछ बिंदुओं पर असहमत हैं, फिर भी मैं आपके विचारों का सम्मान करता हूं क्योंकि यह स्पष्ट है कि आपके पास अपना रुख लेने का एक अच्छा कारण है। इसे यथोचित रूप से समाप्त करने के लिए धन्यवाद और बहुत अच्छी रात है। : P
मशीन तनु

2

यदि stdoutआपकी समस्या के लिए पुनर्निर्देशन काम करता है, तो ग्रिंगो सुवे का उत्तर यह कैसे करना है के लिए एक अच्छा प्रदर्शन है।

इसे और भी आसान बनाने के लिए , मैंने कथन का उपयोग करते हुए एक संक्षिप्त सामान्यीकृत कॉलिंग सिंटैक्स के लिए संदर्भों का उपयोग करने वाला एक संस्करण बनाया with:

from contextlib import contextmanager
import sys

@contextmanager
def redirected_stdout(outstream):
    orig_stdout = sys.stdout
    try:
        sys.stdout = outstream
        yield
    finally:
        sys.stdout = orig_stdout

इसका उपयोग करने के लिए, आप बस निम्नलिखित करें (सुवे के उदाहरण से व्युत्पन्न):

with open('out.txt', 'w') as outfile:
    with redirected_stdout(outfile):
        for i in range(2):
            print('i =', i)

यह printतब चुनिंदा रूप से पुनर्निर्देशित करने के लिए उपयोगी है जब कोई मॉड्यूल आपको पसंद नहीं करता है। एकमात्र नुकसान (और यह कई स्थितियों के लिए डीलर है) यह है कि यह काम नहीं करता है अगर कोई अलग-अलग मूल्यों के साथ कई धागे चाहता है stdout, लेकिन इसके लिए एक बेहतर, अधिक सामान्यीकृत विधि की आवश्यकता होती है: अप्रत्यक्ष मॉड्यूल पहुंच। आप इस प्रश्न के अन्य उत्तरों में उस के कार्यान्वयन को देख सकते हैं।


0

Sys.stdout का मान बदलने से प्रिंट करने के लिए सभी कॉल का गंतव्य बदल जाता है। यदि आप प्रिंट के गंतव्य को बदलने के लिए वैकल्पिक तरीके का उपयोग करते हैं, तो आपको समान परिणाम मिलेगा।

आपका बग कहीं और है:

  • यह आपके द्वारा आपके प्रश्न के लिए हटाए गए कोड में हो सकता है (फ़ाइल खोलने के लिए फ़ाइल नाम कहां से आता है?)
  • यह भी हो सकता है कि आप डेटा के फ्लश होने की प्रतीक्षा नहीं कर रहे हैं: यदि आप किसी टर्मिनल पर प्रिंट करते हैं, तो डेटा को हर नई लाइन के बाद फ्लश किया जाता है, लेकिन यदि आप किसी फ़ाइल पर प्रिंट करते हैं, तो यह केवल तभी फ्लश होता है जब स्टडआउट बफ़र पूर्ण होता है (4096 बाइट्स अधिकांश प्रणालियों पर)।

-1

छोरों के लिए प्रिंट फ़ंक्शन का विस्तार करने के लिए कुछ

x = 0
while x <=5:
    x = x + 1
    with open('outputEis.txt', 'a') as f:
        print(x, file=f)
    f.close()

उपयोग करने की आवश्यकता नहीं है और उपयोग whileकरते समय फ़ाइल को बंद करने की आवश्यकता नहीं हैwith
डैनियल स्ट्रेकाबोस्को
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.