打电话时很奇怪 pg_dump

Weirdness with pexpect when calling pg_dump

对不起,如果不允许,我还是新手所以请提前原谅我。我对我注意到的行为很好奇,并希望获得一些意见。

当调用 pg_dump 时,您现在似乎需要输入一个用户提升的密码,所以我在这里的选项是有限的,使用选项是使用 pexpect 来传递短语。

不过,在发送该行之后,什么也没有发生,当登录到一个文件时,我只能看到正在发送的密码,但没有输出。我 double/triple 检查了我的命令并且它可以工作(使用 cli),所以下面的代码片段应该工作得很好。

我尝试 child.logfile_read 来确定预期的输出,我的 child.expect 也是正确的。

password='test'
cmd = 'pg_dump --host {host} --port {port} --dbname {db} --username {username}\
    --file {filename} --table {table} --schema={schema}'.format(
        host=host,
        port=port,
        db=db,
        username=username,
        filename=filename,
        table=table,
        schema=schema
    )


child = pexpect.spawn(cmd)
child.expect('Password:')
child.sendline(password)
child.read()

我只是 碰巧 添加了一个 child.read() 和繁荣,我的文件按预期导出了。这对我来说是错误的,我尝试了几种不同的方法并通读了文档,但我似乎无法理解这确实有效的事实。我的意思是,根据 documentation

This reads at most “size” bytes from the file (less if the read hits EOF before obtaining size bytes). If the size argument is negative or omitted, read all data until EOF is reached. The bytes are returned as a string object. An empty string is returned when EOF is encountered immediately

为什么这真的有效?我错过了什么?我觉得这些是其中一种情况,稍后它会轰炸我,因为我实际上并不了解引擎盖下发生的事情。

我最好的猜测是 EOF 发生了一些奇怪的事情,命令实际上没有在处理,但是当我使用 child.read() 时,它实际上正在完成命令?说实话,不确定。

关键字是EOF。

正如您发布的预期文档的摘录所暗示的那样,read 读取指定数量的字节或直到遇到 EOF。在您的上下文中,这意味着它 等待 以便 child 进程发送 EOF,这相当于进程终止。

如果不调用 read,您的 Python 进程不会阻塞,直到 child 进程完成。它在 child.sendline(password) 调用 returns.

后立即结束

根据您使用 spawn 的事实判断,我假设您是 运行 在 POSIX 平台上。这意味着,预期 child is an instance of ptyprocess.PtyProcessPtyProcess class 实现了 __del__ 终结器,旨在...

[...] make[s] sure that no system resources are left open.

终结器 calls the close method on the instance. That closes the file descriptor and calls terminate 结束 child 进程,通过 SIGINT、SIGHUP 或如果使用 force=True(默认)调用,则最终是 SIGKILL。

因此,当您的 Python 进程结束时,就在 child.sendline(password) returns 之后,解释器开始清理其内存 space 并在进程中执行终结器。这甚至在开始写入输出文件之前就终止了 pg_dump 命令的执行。

在 child 进程完成之前,您必须阻止主进程。 read 确实如此,但您似乎对阅读 child 并不特别感兴趣。您可以改用 wait()

This waits until the child exits. This is a blocking call. This will not read any data from the child [...]