如何在控制台上的同一位置写入输出?

Posted

技术标签:

【中文标题】如何在控制台上的同一位置写入输出?【英文标题】:How do I write output in same place on the console? 【发布时间】:2010-10-05 18:02:36 【问题描述】:

我是python新手,正在编写一些脚本来自动从FTP服务器等下载文件。我想显示下载的进度,但我希望它保持在同一个位置,例如:

输出:

下载文件 FooFile.txt [47%]

我试图避免这样的事情:

     Downloading File FooFile.txt [47%]
     Downloading File FooFile.txt [48%]
     Downloading File FooFile.txt [49%]

我该怎么做呢?


重复:How can I print over the current line in a command line application?

【问题讨论】:

您可能对这个易于使用的模块感兴趣,它是一个文本进度条。 pypi.python.org/pypi/progressbar/2.2 【参考方案1】:

在 python 3 中,函数 print 可以获取许多参数。 函数 print 的完整签名是: print(args*, sep=' ', end='\n', file=sys.stdout, flush=False)

sep 是来自args* 的参数的分隔符时,end 是如何结束打印行('\n\ 表示新行)文件是打印输出的位置(stdout 是领事) 和 flush 是如果要清理缓冲区。

使用示例

import sys

a = 'A'
b = 0
c = [1, 2, 3]

print(a, b, c, 4, sep=' * ', end='\n' + ('-' * 21), file=sys.stdout, flush=True)

输出

A * 0 * [1, 2, 3] * 4
---------------------

在python中有很多方法可以格式化字符串,甚至是内置的格式化字符串类型。

如何格式化字符串

    format() 函数。 (some examples) 格式化字符串文字或通用名称f-strings。 格式使用 % (more about this)

示例

name = 'my_name'

>>> print('my name is: '.format(name))
my name is: my_name

# or
>>> print('my name is: user_name'.format(user_name=name))
my name is: my_name

# or
>>> print('my name is: 0'.format(name))
my name is: my_name

# or using f-strings
>>> print(f'my name is: name')
my name is: my_name

# or formatting with %
>>> print('my name is: %s' % name)
my name is: my_name

【讨论】:

第一个例子有“sys.sdtout”给出了一个语法错误。更改为“sys.stdout”。【参考方案2】:

Python 2

我喜欢以下内容:

print 'Downloading File FooFile.txt [%d%%]\r'%i,

演示:

import time

for i in range(100):
    time.sleep(0.1)
    print 'Downloading File FooFile.txt [%d%%]\r'%i,

Python 3

print('Downloading File FooFile.txt [%d%%]\r'%i, end="")

演示:

import time

for i in range(100):
    time.sleep(0.1)
    print('Downloading File FooFile.txt [%d%%]\r'%i, end="")

带有 Python 3 的 PyCharm 调试器控制台

# On PyCharm Debugger console, \r needs to come before the text.
# Otherwise, the text may not appear at all, or appear inconsistently.
# tested on PyCharm 2019.3, Python 3.6

import time

print('Start.')
for i in range(100):
    time.sleep(0.02)
    print('\rDownloading File FooFile.txt [%d%%]'%i, end="")
print('\nDone.')

【讨论】:

在 python 3+ 上使用这个: print('Downloading File FooFile.txt [%d%%]\r'%i, end="") 在 PyCharm 调试器控制台上,\r 需要出现在文本之前。否则,文本可能根本不会出现,或者出现不一致。我添加了适合我的版本作为编辑,因为我无法在这个答案中编写多行代码。我把它放在我的要点上,这样人们就可以在编辑等待批准时查看它:gist.github.com/yulkang/40168c7729a7a7b96d0116d8b1bc26df 字符串末尾的 "\r" 在 PyCharm 2020.1(PyCharm 2020.1.2(社区版)的调试器控制台中对我有用;构建 #PC-201.7846.77,构建于 5 月 31 日, 2020)。【参考方案3】:

对于 Python 3xx:

import time
for i in range(10):
    time.sleep(0.2) 
    print ("\r Loading... ".format(i)+str(i), end="")

【讨论】:

【参考方案4】:
x="A Sting "
   for i in range(0,1000000):
y=list(x.format(i))
print(x.format(i),end="")

for j in range(0,len(y)):
    print("\b",end="")

【讨论】:

【参考方案5】:

一个对我有用的巧妙解决方案是:

from __future__ import print_function
import sys
for i in range(10**6):
    perc = float(i) / 10**6 * 100
    print(">>> Download is % complete      ".format(perc), end='\r')
    sys.stdout.flush()
print("")

sys.stdout.flush 很重要,否则它会变得非常笨拙,而 for 循环退出上的 print("") 也很重要。

更新:如 cmets 中所述,print 也有一个 flush 参数。因此,以下内容也将起作用:

from __future__ import print_function
for i in range(10**6):
    perc = float(i) / 10**6 * 100
    print(">>> Download is % complete      ".format(perc), end='\r', flush=True)
print("")

【讨论】:

在现代 Python 中,您可以将 flush=True 的 arg 提供给 print,因此不需要额外的 sys.stdout.flush() 调用。【参考方案6】:

也可以使用回车:

sys.stdout.write("Download progress: %d%%   \r" % (progress) )
sys.stdout.flush()

【讨论】:

非常常见和简单的解决方案。注意:如果你的线长于终端的宽度,这会变得很丑。 我还必须添加对 sys.stdout.flush() 的调用,这样光标就不会反弹 是否可以用多行来做到这一点?假设我有三个不同的下载,我想在自己的行上显示每个下载的进度。 我喜欢把\r放在行首,加上\x1b[K清除前面的文字。 python 3 最简单​​的解决方案似乎是:print("sample text", end='\r", flush=True)【参考方案7】:
#kinda like the one above but better :P

from __future__ import print_function
from time import sleep

for i in range(101):
  str1="Downloading File FooFile.txt [%]".format(i)
  back="\b"*len(str1)
  print(str1, end="")
  sleep(0.1)
  print(back, end="")

【讨论】:

为什么比上面的好(我是 Python n00b,所以请原谅我的无知:-))?【参考方案8】:

使用像curses module这样的终端处理库:

curses 模块提供了curses 库的接口,curses 库是便携式高级终端处理的事实标准。

【讨论】:

不适用于 Windows。 @Diego 现在有一个支持库,用于 Windows 上的 curses 模块。见***.com/a/19851287/1426237【参考方案9】:

多次打印退格符\b,然后用新号码覆盖旧号码。

【讨论】:

有趣,我没想到会那样做。 我喜欢这个,因为它不会清除以前的命令(如果你有多个阶段要留在屏幕上) 使用回车(例如print 'Downloading.... \r')也不会清除以前的数据,但它可以避免知道要备份多远。

以上是关于如何在控制台上的同一位置写入输出?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ANSI Escape 代码在控制台上输出彩色文本

从具有相同名称但不同扩展名的文件(*.pdf 和 *.rtf)中,如果 *.rtf 较新,则在控制台上输出消息

如何说服控制台上的 syslog 输出包含时间戳?

如何在 GUI 输出窗口而不是 Visual Studio 2015 中的 cmd 控制台上显示我的 C++ 程序输出?

在 android studio 的控制台上打印

如何避免 SCons 与 -j 参数混合输出?