我正在尝试在后台运行:
nohup script.py > out 2> err < /dev/null &
脚本(
Python 3.4
)在某些时候执行:answer = input('? ')
(它在一个线程中运行着一个菜单)
而且,nohup调用崩溃了:
EOFError: EOF when reading a line
我想象由于
/dev/null
的stdin
重定向。如果我运行时没有stdin
重定向:nohup script.py > out 2> err &
它崩溃与:
OSError: [Errno 9] Bad file descriptor
如果我用以下命令运行它:
script.py > out 2> err
它可以工作,但是会阻止我的终端(它在前台)
如果我用以下命令运行它:
script.py > out 2> err &
它可以在后台运行,但是一旦到达
input
调用,它就会停止。我想要的是:
能够将
stdout
和stderr
重定向到文件系统能够将脚本放在后台
能够移动到前台并正常与菜单交互(因此必须以某种方式启用
stdin
)。 stdout
和stderr
仍将重定向到文件系统,但是stdin
将正常运行。该脚本必须在后台和前台正常运行(当然,菜单在后台不起作用,因为
stdin
是“冻结的”)基本上,我想要的是
stdin
在后台时,它是“冻结的”,并且每当涉及到前台时,它都可以正常工作。这可能吗?解决方案不需要涉及
nohup
最佳答案
带有交互式菜单的所需内容(以及input
的工作方式以及在python下EOF
上失败的方式)意味着您无法在调用程序时安全地将文件作为stdin
传递。这意味着您唯一的选择就是像这样调用它:
$ script.py > out 2> err &
作为演示,这是我的脚本:
from time import sleep
import sys
c = 0
while True:
sleep(0.001)
c += 1
if c % 1000 == 0:
print(c, flush=True)
if c % 2000 == 0:
print(c, file=sys.stderr, flush=True)
if c % 10000 == 0:
answer = input('? ')
print('The answer is %s' % answer, flush=True)
本质上,它将每秒写入
stdout
,每两秒钟将写入stderr
,最后,每十秒钟它将等待输入。如果我要运行此程序并稍等一秒钟(以允许刷新磁盘),并将其链接在一起,如下所示:$ python script.py > out 2> err & sleep 2.5; cat out err
[1] 32123
1000
2000
2000
$
等待至少10秒钟,然后重试
cat out err
:$ cat out err
1000
2000
3000
4000
5000
6000
7000
8000
9000
10000
? 2000
4000
6000
8000
10000
[1]+ Stopped python script.py > out 2> err
$
请注意,由
input
生成的提示也会被写入stdout,并且该程序有效地继续运行,直到它期望stdin
为其提供数据。您只需要通过%
使该进程回到前台,并开始向其提供所需的数据,然后使用^Z
(CtrlZ)挂起,并使用%&
使其在后台再次运行。例:$ %
python script.py > out 2> err
Test input
^Z
[1]+ Stopped python script.py > out 2> err
$ %&
[1]+ python script.py > out 2> err &
$
再等待十秒钟后,再次输入
cat out
:$ cat out
1000
...
10000
? The answer is Test input
11000
...
20000
?
[1]+ Stopped python script.py > out 2> err
$
这本质上是基本的崩溃课程,说明标准进程通常在前台和后台如何工作,并且如果代码正确处理了标准IO,事情就可以按预期工作。
最后,您无法真正做到两全其美。如果应用程序期望使用stdin而未提供任何内容,则clear选项为failure。但是,如果提供了一个,但是应用程序被发送到后台并保持运行,则它将是
Stopped
,因为它期望进一步的输入。如果这种停止的行为是不希望的,则应用程序有问题,除了将EOF
作为其/dev/null
执行时遇到stdin
时,无法更改应用程序,以免导致错误。如果您希望保持stdin
不变,并且应用程序可以在后台运行时保持某种状态,则您不能使用input
函数,因为当stdin
为空时它会阻塞(导致进程停止) )。现在,您已经通过下面的注释澄清了“交互式提示”正在线程中运行,并且由于直接使用
input
来读取stdin
,并且您似乎不愿意修改程序(您要求的是一般情况),但是期望有实用程序为您执行此操作,简单的解决方案是在tmux
或screen
会话中执行此操作,因为它们完全实现了与启动的控制台无关的伪tty(因此,您可以断开并发送会话到后台,或启动其他虚拟会话,请参见手册页),这将提供程序期望的stdio。最后,如果您实际上希望您的应用程序本身支持此功能,则不能直接使用
input
,而是应检查是否可以安全地调用input
(即也许使用select
),或者检查是否该过程当前处于前台或后台(您可能从How to detect if python script is being run as a background process开始工作,尽管您可能想使用sys.stdin
进行检查。)以确定是否可以安全地调用input
(但是,如果用户在输入到来时暂停任务,直到input
等待它仍会挂起),或使用unix套接字进行通信。关于python - 在后台卡住stdin,在前台卡住它,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32598046/