31

我正在尝试调试我编写的可以从标准输入获取其参数的 Python CLI。一个简单的测试用例的输出为

echo "test" | python mytool.py

相当于的输出

python mytool.py test

我想用这个工具调试一些问题,所以我尝试运行它:

echo "test" | pdb mytool.py

但我得到这个输出,然后 pdb 退出:

> /path/to/mytool.py(5)<module>()
-> '''
(Pdb) *** NameError: name 'test' is not defined
(Pdb)

当我添加-m python到 shebang 以及pdb.set_trace()在脚本中运行时,也会发生同样的事情。

这里发生了什么?

4

4 回答 4

16

另一种选择是创建您自己的 Pdb 对象,并在那里设置标准输入和标准输出。我的概念证明涉及 2 个终端,但可以肯定的是,某些工作可以合并到某种非常不安全的网络服务器上。

  1. 创建两个fifo:

    mkfifo fifo_stdin
    mkfifo fifo_stdout
    
  2. 在一个终端中,在后台打开标准输出,然后写入标准输入:

    cat fifo_stdout &
    cat > fifo_stdin
    
  3. 在您的 python 代码/控制台中创建 pdb 对象,并使用它:

    import pdb
    mypdb=pdb.Pdb(stdin=open('fifo_stdin','r'), stdout=open('fifo_stdout','w'))
    ...
    mypdb.set_trace()
    ...
    
  4. 利润!

您应该能够在第一个控制台上使用 pdb。

唯一的缺点是必须使用您的自定义 pdb,但是在 init(PYTHONSTARTUP 或类似的)中进行一些猴子补丁可以提供帮助:

import pdb
mypdb=pdb.Pdb(stdin=open('fifo_stdin','r'), stdout=open('fifo_stdout','w'))
pdb.set_trace=mypdb.set_trace
于 2014-11-17T15:15:59.767 回答
5

您可以使用另一个文件描述符。使用 bash,您可以创建一个新的文件描述符:

exec 3<> test.txt

然后在你的python文件上有类似的东西:

#!/usr/bin/python

# Use fd 3 as another stdin file.
import os
stdin=os.fdopen(3)

while True:
    s=stdin.readline()
    import pdb; pdb.set_trace()
    print len(s)

只需运行您的脚本就会使用该 test.txt 作为输入,并且您可以在标准输入上使用标准输入。如果需要,它也可以与管道一起使用。

于 2014-11-14T16:17:47.213 回答
4

你的控制 TTY 仍然是一个终端,对吧?使用它而不是pdb.set_trace.

def tty_pdb():
    from contextlib import (_RedirectStream,
                            redirect_stdout, redirect_stderr)
    class redirect_stdin(_RedirectStream):
        _stream = 'stdin'
    with open('/dev/tty', 'r') as new_stdin, \
         open('/dev/tty', 'w') as new_stdout, \
         open('/dev/tty', 'w') as new_stderr, \
         redirect_stdin(new_stdin), \
         redirect_stdout(new_stdout), redirect_stderr(new_stderr):
        __import__('pdb').set_trace()

在这些情况下,还没有让 readline 自动完成。向上箭头也不起作用,或者任何其他 readline 细节都不起作用。

于 2018-01-24T19:35:20.323 回答
2

当您使用它为调试命令获取的 pdb(或任何其他 python 调试器)时stdin,这就是您获得 NameError: name 'test' is not defined.

例如,此命令将在运行时请求时退出调试器,并且一次运行不会出现此错误(也不会出现交互式调试):

(echo cont;echo "测试") | python -m pdb mytool.py

于 2014-11-14T16:04:30.763 回答