为什么有些命令将终端“挂起”直到完成?


22

有时您从终端运行一个程序,例如lxpanel。终端不会将您带回到提示,它将挂起。您可以按Ctrl+ C返回到提示,但这将终止lxpanel。但是,按Alt+ F2(会弹出一个窗口以接受命令)并正常运行lxpanel

为什么是这样?从终端运行命令和按Alt+ 时出现的“运行”窗口有什么不同F2

这里仅以lxpanel为例。我在多个程序中都经历过


1
提示:GNU Screen(screen)可以用来“包装”运行时间更长的进程。您可以从中分离出来,回到外壳程序,然后重新连接并查看正在运行的进程的输出。重新连接甚至可以从另一个终端,SSH等完成。可能还有其他程序可以让您执行这种操作。
poplitea

Answers:


28

默认情况下,终端将在前台运行程序,因此,直到程序完成后,您才可以回到Shell。这对于从stdin读取和/或写入stdout的程序很有用-您通常不希望其中的许多一次运行。如果要让程序在后台运行,可以这样启动它:

$ lxpanel &

或者,如果它已经在运行,则可以使用Ctrl+ 挂起它,Z然后运行bg以将其移至后台。无论哪种方式,您都将以新的shell提示结尾,但是程序仍在运行,并且其输出将出现在终端中(因此在您输入时,它可能会突然出现)

一些程序(通常是守护程序)在启动时会分叉一个单独的进程,然后让主进程立即退出。这使程序可以继续运行而不会阻塞您的外壳


那么,当您通过按Alt + f2在“运行”窗口中运行程序时,系统实际上在做什么?(至少在gnome和openbox上,alt + f2可以做到这一点)。我问是因为一旦键入命令,程序就会启动,并且框消失。只是在添加&吗?
sqram 2011年

2
@lyrae:默认情况下,shell在继续执行shell会话之前会等待程序完成,它不会“挂起”(通过“挂起”的任何定义);alt + f2不等待程序。Shell等待程序完成的原因是因为Shell可以将用户输入到Shell中的任何内容重定向到程序的标准输入和/或显示程序的标准输出。由于alt + f2主要用于启动GUI程序,因此alt + f2不提供使用标准输入/输出的可能性,因此不需要等待。
Lie Ryan

1
@lyrae:alt + f2并没有做任何特别的事情来在后台启动程序;它是shell的一项特殊功能,添加'&'是shell的功能。当启动带'&' 的命令时,shell会将程序的标准输入重定向到其自己的标准输入,并将程序的标准输出重定向到其自己的标准输出(这有点做作,因为Shell还提供了许多其他服务,例如拦截Ctrl -C,将SIGINT信号命令发送到前台程序)。“&”告诉外壳程序不要执行这些操作,而只是启动程序(也有人为)。
Lie Ryan

1
@LieRyan您在说外壳程序所做的某些事情实际上是由内核的终端驱动程序处理的,除了外壳程序调用wait()之外,“ with&”通常比“ without&”更“特殊”。 waitpid或等效项),而alt-f2则没有。
2011年

6

在终端中启动程序时,终端将“挂起”直到程序停止。通过按Ctrl+,c您将关闭程序,从而返回到提示。您将在所有GUI应用程序中看到此信息,例如,尝试使用Firefox。

当您使用其他方法(例如Alt + F2)或单击菜单时,您的程序在后台启动,因此不会发生任何奇怪的事情(并且始终没有命令提示符)。

如果您仍然想从终端启动GUI应用,请&在命令末尾附加,如下所示

lxpanel &

这告诉终端lxpanel在后台运行,并立即给您另一个提示。


3

默认情况下,通过外壳程序运行的程序在该外壳程序的前台运行。这将导致外壳挂起操作,并将stdin / stdout / sterr从终端定向到程序。通过桌面环境运行的程序是派生的,这使它们独立于运行它们的程序运行。可以在大多数shell中通过将a附加&到命令上来模拟,尽管这仍将std *连接到终端(尽管从后台程序中的stdin读取会带来更多的复杂性)。


2

与&的背景很好,除了后来返回的需要稍后控制台交互的程序(例如,“ apt -y update&”最终进入STOP状态,因为它想在更长时间后提示用户“真的真的强制?”问题) ....当没有人观看的时候。

要塞住该漏洞并通知进程,终端实际上​​永远不会可用,我在某些命令后附加了<&-,将它们与活动终端完全分离,告知不再需要STDIN。 如果使用/ bin / bash,请确保它是您的外壳。 该脚本将继续记录与没有伪终端相关的任何错误,可以在该伪终端上投射任何提示。

例如:

`./runme.sh &> runme.log <&- & disown`

是我脱离当前终端会话的最终方法。STDOUT和STDERR都记录到runme.log中,无论您的控制台或shell提前终止还是您注销/ su到其他帐户(runme都没有终端垃圾)都没有关系,并且还要感谢即使是父子也可以将其拒绝PID关系已删除。

更新:即使这样,我也很难将信号量与原始父母的名字相关联,所以现在我推荐:

at now <<< "(cmd1; cmd2; etc.) &> logfile.log"

当然,如果要通过电子邮件发送CRON的输出,请删除&>,或将其全部重定向到/ dev / null而不是文件。


一个稍微不那么令人费解的方式来实现,我开始用的就是at now <<< "(cmd1; cmd2; etc.) &> logfile.log"
马科斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.