英文:
How to both redirect output and have a console window for a subprocess?
问题
I want to use subprocess.Popen(["start", "/wait", "program"], shell=True)
to have my program open in a new window. At the same time, I want to be able to capture output (stdout), for example by using subprocess.PIPE
. However, if I simply add the pipe directive (stdout=.. in popen), the pipe is of the start
program which prints nothing.
I tried to follow https://stackoverflow.com/questions/60275345/how-to-redirect-output-from-start-ed-console and use:
v = ["start", "/wait", "program", "^>1"]
but it didn't work (hangs on readline).
I know I can use a log file, but kind of inclined against (because of buffering mainly).
英文:
I want to use
subprocess.Popen(["start", "/wait", "program"], shell=True)
to have my program open in a new window. At the same time, I want to be able to capture output (stdout), for example by using subprocess.PIPE
. However, if I simply add the pipe directive (stdout=.. in popen) , the pipe is of the start
program which prints nothing.
I tried to follow https://stackoverflow.com/questions/60275345/how-to-redirect-output-from-start-ed-console and use :
v = ["start" ,"/wait", "program", "^>1"]
but it didn't work (hangs on readline).
I know I can use log file, but kind of inclined against (because of buffering mainly).
答案1
得分: 2
start
命令将尝试启动名为program
的任何程序作为新进程,如果program
是基于控制台的,则将为其打开一个新的控制台窗口以将输出(和错误)写入,并可能接收输入。
假设您的应用程序program
是基于控制台的,它只有一个stdout
流,控制台窗口将接收并在窗口上回显该流。
如您所发现,重定向start
命令本身的stdout
是无效的,因为它实际上不会将任何内容写入标准输出(当一切正常时)- 它只是用于启动其他程序。
例如,如果您尝试了这样的操作:
start /wait C:\Windows\system32\PING.EXE 8.8.8.8 -t
... 您将在一个新的控制台中看到输出,并且在调用窗口/进程中将看不到任何内容。
如果您尝试像这样重定向输出:
start /wait C:\Windows\system32\PING.EXE 8.8.8.8 -t > test.txt
... 那也不会起作用,因为它只会重定向start
的输出,而start
的输出是空的。
但是这也行不通:
start /wait C:\Windows\system32\PING.EXE 8.8.8.8 -t ^> test.txt
... 因为没有东西可以应用转义的重定向。这就是为什么您链接的问题建议这样做的原因:
start /wait cmd /c C:\Windows\system32\PING.EXE 8.8.8.8 -t ^> test.txt
这几乎起作用了,它启动了进程,打开了窗口并运行了程序,并将输出捕获到一个文件中。但所有这些都是从新进程中完成的,而不是从调用进程中完成的。
然而,您希望program
的文本仍然显示在新的控制台窗口中,并且可以实时访问相同的输出以在脚本中使用(在您的情况下,不是将其重定向到文件中,而是可能以其他方式使用它)。
您可以通过在新控制台中使用PowerShell启动命令来接近此目标,使用Start-Process
而不是cmd /c
,并使用类似于Linux的tee
命令的Tee-Object
。
然而,这只能在新控制台中同时将输出写入文件和控制台,所有这些都是从新控制台完成的。当然,您可以从您的Python脚本中监视文件的更改,但这仍然只会在Tee-Object
将文件缓冲区刷新到磁盘时获取新数据。我认为在Windows中使用普通控制台窗口是无法使其正常工作的,这纯粹是由于它们的工作方式以及您无法仅使用控制台窗口将流从一个进程重定向到另一个进程。
在这里的解决方案可能是编写一个在新控制台窗口中运行的Python脚本,既将数据回显到控制台,又对其进行处理。您只需从原始脚本中启动此辅助脚本,效果就是您需要的。您可能需要提供更多详细信息来解释为什么在您的情况下这不是一个合适的解决方案。
英文:
The start
command will try to start whatever program
is as a new process and if program
is console-based, a new console window will open for it to write output (and errors) to and possibly receive input from.
Assuming your application program
is console-based, it only has a single stdout
stream, which the console window will receive and echo on the window.
As you found, redirecting the stdout
of the start command itself doesn't help, since it doesn't actually write anything to standard out (when all is well) - it only serves to launch the other program.
For example, if you tried something like this:
start /wait C:\Windows\system32\PING.EXE 8.8.8.8 -t
... you would see the output in a new console, and nothing in in the calling window / process.
If you tried to redirect the output like this:
start /wait C:\Windows\system32\PING.EXE 8.8.8.8 -t > test.txt
... that wouldn't work either, since it would just be redirecting the output from start
, which is nothing.
But this also doesn't work:
start /wait C:\Windows\system32\PING.EXE 8.8.8.8 -t ^> test.txt
... since there isn't anything to apply the escaped redirect to. That's why the question you linked suggests this:
start /wait cmd /c C:\Windows\system32\PING.EXE 8.8.8.8 -t ^> test.txt
This almost works, in that it starts the process, opens the window and runs the program, and captures the output in a file. But it does all of this from the new process, not in the calling process.
However, you want the text from the program
to still show up on the new console window, as well as have live access to the same output in your script (in your case not to redirect it to a file, but presumably use it in some other way).
You can get close by starting the command in the new console with PowerShell, using Start-Process
instead of cmd /c
and using Tee-Object
which is similar to the Linux tee
command.
However, this only succeeds in writing the output to a file as well as to the console, all from the new console. You could of course monitor the file for changes from your Python script, but this would still only get you new data whenever Tee-Object
flushes the file buffer to disk. I don't think there's a way for you to get this to work using normal console windows in Windows, simply due to the way those work, and the fact that you can't just redirect a stream from one process to another using console windows.
The solution here might be to write a Python script that runs in the new console window, both echoing the data to the console as well as processing it. You just launch this helper script from your original script and the effect is exactly what you need. You'd have to provide more details to explain why that wouldn't be a suitable solution in your case.
答案2
得分: 0
start
是一个Shell命令,而不是一个独立的程序。Popen
函数重定向运行程序的输出,而不是Shell命令的输出。
我们可以尝试创建一个批处理文件,启动你的程序并将其输出重定向到一个文件,然后使用 Popen
运行这个批处理文件。
让我们创建一个名为 start.bat
的批处理文件,其中包含以下内容:
start /wait program > output.txt
然后我们可以像这样使用 Popen
运行它:
import subprocess
p = subprocess.Popen(["start.bat"], shell=True)
英文:
start
is a shell command, not a separate program. The Popen
function redirects the output of the program it runs, not the output of shell commands.
We could try to create a batch file that starts your program and redirects its output to a file, and then run this batch file with Popen
.
Lets do a start.bat
batch file which contain:
start /wait program > output.txt
Then we can run it with Popen
like that
import subprocess
p = subprocess.Popen(["start.bat"], shell=True)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论