I want to redirect the print to a .txt file using python. I have a 'for' loop, which will 'print' the output for each of my .bam file while I want to redirect ALL these output to one file. So I tried to put
f = open('output.txt','w'); sys.stdout = f
at the beginning of my script. However I get nothing in the .txt file. My script is:
#!/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....
So what's the problem? Any other way besides this sys.stdout?
I need my result look like:
Filename: ERR001268.bam
Readlines finished!
Mean: 233
SD: 10
Interval is: (213, 252)
This works perfectly:
Now the hello will be written to the test.txt file. Make sure to close the
stdout
with aclose
, without it the content will not be save in the fileDon't use
print
, uselogging
You can change
sys.stdout
to point to a file, but this is a pretty clunky and inflexible way to handle this problem. Instead of usingprint
, use thelogging
module.With
logging
, you can print just like you would tostdout
, or you can also write the output to a file. You can even use the different message levels (critical
,error
,warning
,info
,debug
) to, for example, only print major issues to the console, but still log minor code actions to a file.A simple example
Import
logging
, get thelogger
, and set the processing level:If you want to print to stdout:
If you want to also write to a file (if you only want to write to a file skip the last section):
Then, wherever you would use
print
use one of thelogger
methods:To learn more about using more advanced
logging
features, read the excellentlogging
tutorial in the Python docs.The most obvious way to do this would be to print to a file object:
However, redirecting stdout also works for me. It is probably fine for a one-off script such as this:
Redirecting externally from the shell itself is another good option:
Other questions:
What is the first filename in your script? I don't see it initialized.
My first guess is that glob doesn't find any bamfiles, and therefore the for loop doesn't run. Check that the folder exists, and print out bamfiles in your script.
Also, use os.path.join and os.path.basename to manipulate paths and filenames.
Since file object normally contains
write()
method, all you need to do is to pass a file object into its argument.Write/Overwrite to File
Write/Append to File
You may not like this answer, but I think it's the RIGHT one. Don't change your stdout destination unless it's absolutely necessary (maybe you're using a library that only outputs to stdout??? clearly not the case here).
I think as a good habit you should prepare your data ahead of time as a string, then open your file and write the whole thing at once. This is because input/output operations are the longer you have a file handle open, the more likely an error is to occur with this file (file lock error, i/o error, etc). Just doing it all in one operation leaves no question for when it might have gone wrong.
Here's an example:
And then when you're all done collecting your "data lines" one line per list item, you can join them with some
'\n'
characters to make the whole thing outputtable; maybe even wrap your output statement in awith
block, for additional safety (will automatically close your output handle even if something goes wrong):However if you have lots of data to write, you could write it one piece at a time. I don't think it's relevant to your application but here's the alternative:
Something to extend print function for loops