python中stdin.write_关于python:subprocess popen.communicate()与stdin.write()和stdout.read()

我注意到两种方法的两种不同的行为应该导致相同的结果。

目标-使用子过程模块执行外部程序,发送一些数据并读取结果。

外部程序是PLINK,平台是WindowsXP,Python版本3.3。

主要思想

execution=["C:\\Pr..\\...\\plink.exe","-l", username,"-pw","***", IP]

a=subprocess.Popen(execution, bufsize=0, stdout=PIPE, stdin=PIPE, stderr=STDOUT, shell=False)

con=a.stdout.readline()

if (con.decode("utf-8").count("FATAL ERROR: Network error: Connection timed out")==0):

a.stdin.write(b"con rout 1

")

print(a.stdout.readline().decode("utf-8"))

a.stdin.write(b"infodf

")

print(a.stdout.readline().decode("utf-8"))

else:

print("ERROR")

a.kill()

到现在为止还挺好。

现在,我希望能够执行一个循环(每次写入子进程的stdin之后),该循环一直等到子进程的stdout的EOF结束后,打印出来,然后再执行另一个stdin命令,依此类推。

因此,我首先尝试了关于同一主题的先前讨论的内容(子进程命令的实时输出,逐行读取子进程stdout,python,子进程:从子进程读取输出)。

而且它没有用(它永远挂起了),因为PLINK进程一直保持活动状态,直到我自己杀死它为止,因此在stdout为true时无需等待子进程的stdout到达EOF或执行循环,因为在我杀死它之前,它将永远是真的。

所以我决定每次写stdin时都要从stdout读两次(对我来说足够好了)-

execution=["C:\\Pr..\\...\\plink.exe","-l", username,"-pw","***", IP]

a=subprocess.Popen(execution, bufsize=0, stdout=PIPE, stdin=PIPE, stderr=STDOUT, shell=False)

con=a.stdout.readline()

if (con.decode("utf-8").count("FATAL ERROR: Network error: Connection timed out")==0):

a.stdin.write(b"con rout 1

")

print(a.stdout.readline().decode("utf-8"))

print(a.stdout.readline().decode("utf-8"))   //the extra line [1]

a.stdin.write(b"infodf

")

print(a.stdout.readline().decode("utf-8"))

print(a.stdout.readline().decode("utf-8"))   //the extra line [2]

else:

print("ERROR")

a.kill()

但据我所知,第一个额外的readline()会永远挂起,原因与我提到的原因相同。第一个额外的readline()永远等待输出,因为唯一的输出已在第一个readline()中读取,并且由于PLINK处于活动状态,因此该函数仅"坐在"那里并等待一条新的输出线。

因此,我尝试了此代码,并期望出现相同的挂起,因为PLINK直到我将其杀死后才会死亡-

execution=["C:\\Pr..\\...\\plink.exe","-l", username,"-pw","***", IP]

a=subprocess.Popen(execution, bufsize=0, stdout=PIPE, stdin=PIPE, stderr=STDOUT, shell=False)

con=a.stdout.readline()

if (con.decode("utf-8").count("FATAL ERROR: Network error: Connection timed out")==0):

a.stdin.write(b"con rout 1

")

print(a.stdout.readline().decode("utf-8"))

a.stdin.write(b"infodf

")

print(a.stdout.readline().decode("utf-8"))

print(a.communicate()[0].decode("utf-8"))     //Popen.communicate() function

else:

print("ERROR")

a.kill()

我尝试了该操作,因为根据communicate()的文档,该功能要等到过程结束后再完成。同样,它从stdout读取直到EOF。 (与写入和读取stdout和stdin相同)

但是communicate()完成并且没有挂起,与上一个代码块相反。

我在这里想念什么?为什么在使用communicate()时PLINK结束,但是在使用readline()时却没有结束?

您的程序没有communicate()死锁,因为这两个进程在互相写东西之前都互相等待着写东西。

在您的示例中,communicate()不会死锁,因为它会像命令a.stdin.close()那样关闭流。这会将EOF发送到您的子进程,让它知道不再有输入,因此可以关闭自身,这又关闭其输出,因此a.stdout.read()最终返回EOF(空字符串)。

您的主进程将不会从子进程收到任何特殊信号,以让您知道它已经完成了从一个命令写入结果的准备,但已准备好用于另一个命令。

这意味着要像您尝试的那样与一个子流程来回通信,必须阅读该子流程发送的确切行数。如您所见,如果您尝试读取过多行??,则会陷入僵局。您也许可以使用您所知道的信息(例如,发送的命令以及到目前为止所看到的输出)来确定要读取的行数。

如果您不想在打开的进程中遇到死锁,请像通常使用键盘Enter( n)发送一样在输入后发送EOF信号。 因此,使用此功能可以避免死锁。 proc.stdin.write(b2 + 2 n),proc.stdin.flush(),print(proc.stdout.readline()。decode())

@ babygame0ver n是行尾,而不是文件尾。 您可以在原始帖子中看到他们已经在发送换行符。 您似乎在想一个特定的过程,该过程总是每行输入响应一行输出。 并非总是如此。

您可以使用线程同时进行读写,尤其是在仅需要将输出打印给用户的情况下:

from threading import Thread

def print_remaining(stream):

for line in stream:

print(line.decode("utf-8"))

con = a.stdout.readline()

if"FATAL ERROR" not in con.decode("utf-8"):

Thread(target=print_remaining, args=[a.stdout]).start()

for cmd in LIST_OF_COMMANDS_TO_SEND:

a.stdin.write(cmd)

我知道我可以用。 请注意我的问题。

事实是,使用subprocess.Popen时,即使在过程终止之前,代码仍会继续读取。尝试将.wait()附加到您的Popen调用中(请参阅文档),

a=subprocess.Popen(execution, bufsize=0, stdout=PIPE, stdin=PIPE, stderr=STDOUT, shell=False).wait()

这将确保执行完成之后再进行其他操作。

抱歉,它不能回答我的问题。 我知道这个事实:)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值