我的最终目标是从一个Python脚本开始,另一个Python脚本使用终端作为用户对话框GUI来询问文件名,然后通过另一个脚本退出到终端打印选定的文件名。
我试过使用os.system()
和subprocess.Popen()
在所有我已知的可能的变体,但未能实现我的目标.查询互联网几个小时和几天没有帮助.进程间通信和重定向的stdout和stdin的问题似乎很难解释.
使用os.system("gnome-terminal")
,我可以在不阻塞Python脚本的情况下启动终端,使用PyAutoGUI,我应该可以在终端shell中启动另一个脚本,但我仍然不知道如何处理将另一个脚本的结果打印到命令行的问题。
在我自己解决上述问题的过程中,我希望通过了解标题中所述问题的答案来提高我对启动应用程序以及重定向stdin和stdout工作原理的理解。
下面是代码:
import os, sys
os.system("gnome-terminal")
print('''OK after os.system("gnome-terminal") ''')
sys.exit()
它启动终端、打印并退出。
这里是启动计算器后被阻止的代码:
import os, sys
os.system("gnome-calculator")
print('''OK after os.system("gnome-calculator") ''')
sys.exit()
在关闭计算器窗口之前无法打印“挂起”。
考虑到 bigkeefer 在注解中给出的关于派生应用程序的进程ID的提示,我尝试找出gnome-calculator、gnome-terminal和SciTE之间的区别(也不会阻塞)。看起来已经在运行并且不允许多个示例的应用程序不会阻塞。gnome终端看起来只是所有打开窗口的一个示例。所以如果一个新的命令被shell命令启动,它总是已经在那里了。2这解释了我观察到的行为上的差异,但是......仍然没有回答这个问题,* 为什么 * 是这样的?
~ $ gnome-calculator &
[1] 18115
~ $ gnome-calculator &
[2] 18122
[1] Done gnome-calculator
~ $ SciTE &
[3] 18141
[2] Done gnome-calculator
~ $ SciTE &
[4] 18142
[3] Done SciTE
~ $ SciTE &
[5] 18150
[4] Done SciTE
~ $ SciTE
[5]+ Done SciTE
~ $ SciTE
~ $ SciTE
~ $ SciTE &
[1] 18183
~ $ SciTE &
[2] 18187
[1] Done SciTE
~ $ gnome-terminal
[2]+ Done SciTE
~ $
最奇怪的似乎是在启动gnome-terminal之后来自shell的关于SciTE的反馈(见最后三行)。
2条答案
按热度按时间flseospp1#
我还不能提供任何关于 * 为什么 * 它是这样的细节,但我可以(在我的问题的评论的帮助下)解释gnome计算器和gnome终端应用程序之间的区别是什么,这 * 可能 * 导致观察到的不同的阻塞行为。
启动一个gnome-terminal并不会启动一个具有新进程ID的终端示例,因为终端应用程序(gnome-terminal-server)已经在运行,并且不允许自身有多个示例(只能有多个窗口)。始终只有一个gnome-terminal-server在运行。
启动gnome-calculator将启动具有另一个进程ID的新示例。Gnome Calculator允许创建自身的多个独立示例。
一般来说,已经运行且不允许自身多个示例的应用程序似乎不会阻塞尚未运行或允许自身多个示例的应用程序。
tkqqtvp12#
我怀疑答案是所有从终端执行的应用程序实际上都以完全相同的方式运行("阻塞" shell),直到它们被终止;由用户或由程序自身退出:干净地(退出状态0)、具有错误(退出状态非0)或崩溃)。
正如在评论中所讨论的,如果需要,可以使用作业控制和其他方法来解决这个问题(尽管现在大多数人只是在他们的终端上打开另一个选项卡等等)。但是,您也可以完全脱离shell(例如,使用bash,其他shell会有所不同),方法是使用:
从gnome-terminal的行为来看,这是因为它执行并实际生成了gnome-terminal-server(或者,大概,告诉它打开另一个终端窗口,如果它已经在运行),然后终止自己。因此,你的 shell "返回给你"(不再"阻止"),因为程序(gnome终端)你跑了(几乎)立即退出(在本例中状态为0),因为它的工作实际上是与另一个程序进行短暂通信或运行该程序(结果是它现在没有连接到shell。即它已被gnome终端分叉)。例如:
侏儒终端执行(pid 4313),生成gnome服务器终端(如果还没有运行,我假设它已经运行了,那么它会请求另一个终端窗口),然后自行终止。
ps 4313
没有返回任何内容,对于这个实验输出,这并不奇怪,因为我们可以看到作业2确实已经结束了。当然,这不是我们最初看到的样子!(或者是任何从"表面价值"/表面上看的人)一旦关闭了所有的gnome终端窗口,服务器进程也将停止运行(直到再次执行gnome-terminal)。
我怀疑那些不允许自身有多个示例的应用程序实际上最初是在shell中执行的,检测到一个示例已经在运行,然后立即终止。因此,没有"阻塞",因为它们实际上不再运行。(您的shell可能会被阻塞几毫秒)
根据应用程序的不同,它可能会也可能不会显示一条消息(stderr)来告诉用户这一点。如果它不显示,它看起来没有阻塞,因为它被执行并几乎立即再次终止。
只是需要注意的是,我不是这方面的Maven,但这是我对它的理解...
在shell命令的末尾添加一个&符号使其成为一项后台任务,从而将shell提示符的控制权直接交还给您,这样您就可以继续工作,而无需等待作业完成(从而让你的shell提示符回来)。结果,你刚刚运行的命令是由shell job control系统管理的。你可以在它运行的时候继续做你的sysadmin之类的事情,这会告诉你什么时候后台工作完成了(例如你看到的
[2]+ done
消息).这在我们这里的例子中不是特别有用,但是想象一下在一个大的文件系统上运行一个find命令可能要花几个小时.在后台运行这个命令,你可以在它做它的事情的时候继续工作.但是
stdout
和stderr
仍然返回到您的终端(除非您重定向它)。shell正在处理所有这些作业,如果shell死亡,它们都将死亡。这将我们带到nohup
。例如,如果终端窗口关闭,则它接收SIGHUP(代表信号hangup--它可以追溯到串行线时代!大多数,如果不是全部,现代shell现在会拦截这个信号,并在终止之前基本上决定/弄清楚如何处理它正在运行的作业)。还有其他发送它的方法,但这可能会导致一个相对大的主题,所以,对于这种情况,只需说明,运行前面带有
nohup
的命令会告诉shell忽略输入并将stdout保存到文件中,而不是保存到该命令中,同时还使该命令"不受"挂起/断开的影响。(note在运行第一个命令后立即返回提示符)。使用
nohup
执行的任何操作也由作业系统管理。(You我还将在下面的示例中看到shell如何处理SIGHUP的演示,其中包括
disown
的功能。)关于仅使用"与"和
gnome-calculator 2> /dev/null & disown
之间的区别,您可以在终端中执行以下示例:现在让calculator继续运行,但是通过点击窗口的X关闭你的终端。gnome-calculator将随之消亡。
打开终端并再次运行上面的命令,但这次按CTRL-D键关闭终端。这时您应该会看到
exit
在shell中出现大约两秒钟,然后它停止运行--但calculator继续运行。这几秒钟是您的shell拦截信号(CTRL-D)并决定放弃它的作业进程(如果可能的话),以便它们在shell终止之前继续运行。现在运行:
点击窗口中的X关闭终端。Calculator这次不会被破坏,因为你已经明确告诉shell在它第一次执行时将它从自身分离。所以上面的命令告诉shell忽略stdout和stderr。在后台运行calc,但也立即放弃它(基本上使calc成为自己的进程,不再“绑定”到shell)。这样calc就可以生存,而不管shell发生了什么(无论是不同的挂起信号到shell还是shell崩溃等等)。