如何重定向“打印”输出到文件?
我想使用 Python 将打印重定向到 .txt 文件。我有一个 for
循环,它将打印
每个 .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/xxx/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!'
那么问题出在哪里?除了这个 sys.stdout 之外还有其他方法吗?
我需要我的结果如下:
Filename: ERR001268.bam
Readlines finished!
Mean: 233
SD: 10
Interval is: (213, 252)
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 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/xxx/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!'
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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
最明显的方法是打印到文件对象:
但是,重定向标准输出也适用于我。对于像这样的一次性脚本来说可能没问题:
从 Python 3.4 开始,有一个简单的上下文管理器可以用来执行此操作 在标准库中:
从 shell 本身进行外部重定向是另一种选择,通常更可取:
其他问题:
脚本中的第一个文件名是什么?我没有看到它初始化。
我的第一个猜测是 glob 找不到任何 bamfile,因此 for 循环不会运行。检查该文件夹是否存在,并打印脚本中的 bamfiles。
另外,使用 os.path.join 和 os.path.basename 来操作路径和文件名。
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:
Since Python 3.4 there's a simple context manager available to do this in the standard library:
Redirecting externally from the shell itself is another option, and often preferable:
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.
您可以使用
file
参数重定向打印(在 Python 2 中,有>>
运算符)。在大多数情况下,您最好只正常写入文件。
或者,如果您想在多个项目之间写入空格,例如
print
:You can redirect print with the
file
argument (in Python 2 there was the>>
operator instead).In most cases, you're better off just writing to the file normally.
or, if you have several items you want to write with spaces between, like
print
:Python 2 或 Python 3 API 参考:
由于 文件对象 通常包含
write() 方法,您需要做的就是传递一个 文件对象 进入其论点。
写入/覆盖文件
写入/追加到文件
Python 2 or Python 3 API reference:
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
不要使用
print
,使用logging
您可以更改
sys.stdout
以指向文件,但这是一种相当笨拙且不灵活的方式来处理这个问题。不要使用print
,而是使用logging
模块。使用
logging
,您可以像stdout
一样进行打印,也可以将输出写入文件。您甚至可以使用不同的消息级别(严重
、错误
、警告
、信息
、调试<例如,仅将主要问题打印到控制台,但仍将次要代码操作记录到文件中。
一个简单的示例
导入
logging
,获取logger
,并设置处理级别:如果您想打印到 stdout:
如果您还想写入文件(如果您只想写入文件,请跳过最后一部分):
然后,无论您在何处使用
print
,都可以使用logger
方法之一:了解有关使用更高级
的更多信息>logging
功能,阅读优秀的Python 文档中的日志记录
教程。Don'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.这非常有效:
现在 hello 将被写入 test.txt 文件。确保使用
close
关闭stdout
,否则内容将不会保存在文件中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 file最简单的解决方案不是通过Python;而是通过Python。它穿过外壳。从文件的第一行 (
#!/usr/bin/python
) 我猜测您使用的是 UNIX 系统。只需像平常一样使用print
语句,并且根本不要在脚本中打开该文件。当您要运行文件时,不要运行文件,而是使用
将
替换为您希望输出进入的文件的名称。>
标记告诉(大多数)shell 将 stdout 设置为以下标记描述的文件。这里需要提到的一件重要的事情是“script.py”需要成为可执行文件才能运行。
所以在运行
./script.py
之前,执行这个命令chmod a+x script.py
(使脚本对所有用户可执行)
The easiest solution isn't through python; its through the shell. From the first line of your file (
#!/usr/bin/python
) I'm guessing you're on a UNIX system. Just useprint
statements like you normally would, and don't open the file at all in your script. When you go to run the file, instead ofto run the file, use
where you replace
<filename>
with the name of the file you want the output to go in to. The>
token tells (most) shells to set stdout to the file described by the following token.One important thing that needs to be mentioned here is that "script.py" needs to be made executable for
./script.py
to run.So before running
./script.py
,execute this commandchmod a+x script.py
(make the script executable for all users)
如果您使用 Linux,我建议您使用
tee
命令。实现是这样的:如果您不想更改代码中的任何内容,我认为这可能是最好的解决方案。您也可以实现记录器,但需要对代码进行一些更改。
If you are using Linux I suggest you to use the
tee
command. The implementation goes like this:If you don't want to change anything in the code, I think this might be the best possible solution. You can also implement logger but you need do some changes in the code.
您可能不喜欢这个答案,但我认为这是正确的。除非绝对必要,否则不要更改您的标准输出目的地(也许您正在使用仅输出到标准输出的库???显然不是这里的情况)。
我认为作为一个好习惯,您应该提前将数据准备为字符串,然后打开文件并立即写入整个内容。这是因为输入/输出操作打开文件句柄的时间越长,该文件就越有可能发生错误(文件锁定错误、I/O 错误等)。只需在一次操作中完成所有操作,就不会出现什么时候可能出错的问题。
这是一个示例:
然后,当您完成每个列表项一行的“数据行”收集后,您可以使用一些
'\n'
字符将它们连接起来,以使整个内容可输出;甚至可能将您的输出语句包装在with
块中,以提高安全性(即使出现问题也会自动关闭您的输出句柄):但是,如果您有大量数据要写入,您可以一次写一篇。我认为这与您的应用程序无关,但这是替代方案:
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:
如果重定向
stdout
可以解决您的问题,Gringo Suave 的答案 很好地演示了如何操作它。为了使它更容易,我使用 制作了一个版本contextmanagers 使用
with
语句获得简洁的通用调用语法:要使用它,您只需执行以下操作(源自 Suave 的示例):
它对于选择性重定向很有用
print
当模块以您不喜欢的方式使用它时。唯一的缺点(这在很多情况下都是破坏因素)是,如果想要多个线程具有不同的 stdout 值,那么它就不起作用,但这需要一种更好、更通用的方法:间接模块使用权。您可以在这个问题的其他答案中看到它的实现。If redirecting
stdout
works for your problem, Gringo Suave's answer is a good demonstration for how to do it.To make it even easier, I made a version utilizing contextmanagers for a succinct generalized calling syntax using the
with
statement:To use it, you just do the following (derived from Suave's example):
It's useful for selectively redirecting
print
when a module uses it in a way you don't like. The only disadvantage (and this is the dealbreaker for many situations) is that it doesn't work if one wants multiple threads with different values ofstdout
, but that requires a better, more generalized method: indirect module access. You can see implementations of that in other answers to this question.这是我用来打印到文件/日志的另一种方法...修改内置打印函数,以便它使用当前时间戳记录到临时目录中的文件,并打印到标准输出。在脚本中执行此操作的唯一真正优点是不必去修改现有的打印语句。
将原始打印函数复制到新变量
覆盖现有打印函数
显示文件
删除文件
Here's another method I've used for printing to a file/log... Modify the built-in print function so that it logs to a file in the temp directory with the current time stamp, as well as print to stdout. The only real advantage to doing this within a script is not having to go and modify existing print statements.
Copy original print function to new variable
Overwrite existing print function
display file
remove file
我可以使用以下方法破解这个问题。它将使用此打印函数而不是内置打印函数并将内容保存到文件中。
I am able to crack this using the following method. It will use this print function instead of builtin print function and save the content to a file.
更改 sys.stdout 的值确实会更改所有打印调用的目的地。如果您使用其他方法来更改打印目的地,您将得到相同的结果。
您的错误在其他地方:
Changing the value of sys.stdout does change the destination of all calls to print. If you use an alternative way to change the destination of print, you will get the same result.
Your bug is somewhere else:
在 python 3 中,您可以重新分配
print
:请注意,
other_fn
中的 print 仅切换输出,因为 print 正在被转换。在全局范围内重新分配。如果我们在函数内分配print,other_fn
中的print通常不会受到影响。如果我们想影响所有 print 调用,我们可以使用 global 关键字:就个人而言,我更愿意回避使用
print
函数的要求通过将输出文件描述符烘焙到一个新函数中:In python 3, you can reassign
print
:Note that the print from
other_fn
only switches outputs because print is being reassigned in the global scope. If we assign print within a function, the print inother_fn
is normally not affected. We can use the global keyword if we want to affect all print calls:Personally, I'd prefer sidestepping the requirement to use the
print
function by baking the output file descriptor into a new function:我过去用来输出一些字典的东西如下:
输出的文件如下所示:
Something that I have used in the past to output some dictionaries is the following:
The outputted file will look something like below:
扩展循环打印功能的东西
Something to extend print function for loops