我在 bash 脚本中通过/usr/bin/timeout 执行应用程序时遇到问题。 在此特定情况下,这是一个简单的python结构脚本(结构版本1.14( 要安装此版本的结构库,请运行:pip install "fabric<2" 新织物 2.x 没有复制。
导致问题的外壳脚本:
[root@testhost:~ ] $ cat testNOK.sh
#!/bin/bash
timeout 10 ./test.py
echo "RETCODE=$?"
[root@testhost:~ ] $ ./testNOK.sh
[localhost] run: echo Hello!
RETCODE=124
[root@testhost:~ ] $
类似的脚本(无超时(工作正常
[root@testhost:~ ] $ cat testOK.sh
#!/bin/bash
./test.py
echo "RETCODE=$?"
[root@testhost:~ ] $ ./testOK.sh
[localhost] run: echo Hello!
[localhost] out: Hello!
[localhost] out:
RETCODE=0
[root@testhost:~ ] $
从bash命令行手动执行超时工作正常:
[root@testhost:~ ] $ timeout 10 ./test.py && echo "RETCODE=$?"
[localhost] run: echo Hello!
[localhost] out: Hello!
[localhost] out:
RETCODE=0
[root@testhost:~ ] $
Python2.7 test.py 脚本
[root@testhost:~ ] $ cat test.py
#!/usr/bin/python
from fabric.api import run, settings
with settings(host_string='localhost', user='root', password='XXXXX'):
run('echo Hello!')
[root@testhost:~ ] $
我在不同的 Linux 发行版上观察到相同的行为。
现在的问题是为什么在 bash 脚本中通过超时执行的应用程序以不同的方式运行,这个问题的最佳解决方案是什么?
您需要使用--foreground
选项调用timeout
:
timeout --foreground ./test.py
仅当timeout
命令不是从交互式 shell 执行(即,如果从脚本文件执行(时,才需要执行此操作。
引用timeout
信息页面:
‘--foreground’
Don’t create a separate background program group, so that the
managed COMMAND can use the foreground TTY normally. This is
needed to support timing out commands not started directly from an
interactive shell, in two situations.
1. COMMAND is interactive and needs to read from the terminal for
example
2. the user wants to support sending signals directly to COMMAND
from the terminal (like Ctrl-C for example)
在这种情况下,实际发生的事情是结构(或调用的东西(正在调用tcsetattr
以关闭终端回声。我不知道为什么,但我想这与用于(不(收集用户密码的过程有关。(我只是在痕迹中看到它;我没有试图找到电话。尝试从后台进程更改 tty 配置将导致进程阻塞,直到它重新获得对 tty 的控制,这就是正在发生的事情。
不使用timeout
时不会发生这种情况,因为bash
不会创建后台程序组。我想结构 2 避免了对tcsetattr
的调用。
您可能也可以通过避免基于密码的SSH身份验证来避免此问题,但我没有尝试过。
您还可以通过将stdin
重定向到/dev/null
(在timeout
命令或调用 shell 脚本时(来避免此问题。如果您不需要将 stdin 转发到远程命令(您可能不需要(,那也可能很有用。
你可以在不使用 bash 的情况下使用超时 只需使用 python 中的时间模型即可
import time
time.sleep(5)
#change the 5 by the seconds that you need to set a timeout