在Python脚本中检查交互式Shell

33

我需要确定调用我的Python脚本的shell是否处于交互模式下。如果是交互模式,程序应该将输出导向到less(1),以便易于阅读。如果不是,则应该简单地将输出打印到stdout,以允许它被导向打印机、文件或另一个分页器。

在shell脚本中,我会检查提示变量$PS1是否定义,或者在$-变量存储的标志中查找-i选项。

从Python中测试交互性的首选方法是什么?

5个回答

43

这通常足够好用了

import os, sys
if os.isatty(sys.stdout.fileno()):
    ...

24
sys.stdout.isatty() 更短。 - user355252
16
sys.__stdin__.isatty()更可靠。(不受stdin重定向影响,允许通过管道输出) - Evpok
1
@Evpok:OP要求的是stdout,stdin完全无关。为了确定是否分页输出,检查stdin确实是错误的流,因为用户可以将某些内容管道传输到程序中(从而重定向stdin并将其与tty断开连接),仍然希望在分页器中看到输出(因为stdout未被重定向)。 - user355252
1
@Evpok,你是指sys.__stdout__.isatty()吗?当输入不是tty时,输出仍然可能是tty,而且OP似乎对输出感兴趣。 - John La Rooy
5
我知道。但是他确实写了:“如果它处于交互模式下,程序应将输出导向到less(1),以便更容易阅读。” 对我来说,这意味着他会检查 stdin 并根据其性质重定向 stdout - Evpok
@Evpok,@lunaryom 我正在制作一个类似于man(1)的程序。 我希望它的行为大致类似于man,即如果是交互式输出,则将其管道输出到less(1),否则仅打印输出。 因此,我可能需要检查stdout是否为tty。 - jforberg

2

你可以使用这个链接中的相同方法来测试stdin是否与终止(tty)相关联,你可以使用os.isatty()来实现,例如:

>>> os.isatty(0)
True

注意:当您通过ssh远程调用该命令时,相同链接将失败。给出的解决方案是测试stdin是否与管道相关联。

3
我更喜欢更明显的 sys.__stdin__.isatty() - Evpok
@Evpok:是的,同意,我忘了文件对象方法isatty(),谢谢 :) - mouad
这似乎与gnibbler的答案相同,只是读者必须了解足够的Unix知识以知道文件0是stdin。您认为在stdin或stdout上检查isatty()是否有区别? - jforberg
@jforberg: 是的,我同意,并且我认为最好的是@Evpok的评论,sys.__stdin__.isatty(),而据我所知,交互模式意味着stdin关联到终端而不是stdout,如果我错了,请纠正我 :) - mouad
是的,Evpok的解决方案在我看来是最优雅和易读的。谢谢! - jforberg

-4

1
请查看 https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/__init__.py 的第1049行。is_interactive() 只是读取 matplotlib 中的全局变量。我没有看到它保证会引用父 shell 的交互性。 - jforberg

-5

4
只有在使用 Python 命令行带有 -i 选项时才会返回 True。使用 -i 选项启动 Python 后,当脚本执行完后,Python 会进入交互模式。无法使用 sys.flags.interactive 判断当前的 shell 环境。 - chiborg

-9
我为测试制作了一个封面类。
例如,您有:
class SuperInteractiveClass(object):
   def get_data_from_stdin(self):
      '... a lot of code here ...'
   '... and a lot of other function'

我创建了一个第二个类,只是用来测试。
class TestSuperInteractiveClass(SuperInteractiveClass):
    prepared_data = []
    def add_prepared_data(self,data):
        self.prepared_data.append(data)
    def get_data_from_stdin(self):
          return self.prepared_data.pop(0)

我不明白。这有什么意义?这个如何检查调用者的互动性? - Evpok
1
它并没有,至少我无法理解。看起来他已经实现了一个栈。 - jforberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接