python - bash 脚本中的 coreutils 超时对应用程序不透明
问题描述
我在 bash 脚本中通过 /usr/bin/timeout 执行应用程序时遇到问题。在这种特定情况下,这是一个简单的 python 结构脚本(结构版本 1.14) 为了安装此版本的结构库运行: pip install "fabric<2" 新结构 2.x 没有复制。
导致问题的 Shell 脚本:
[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 脚本中通过超时执行的应用程序会以不同的方式表现,以及解决这个问题的最佳方法是什么?
解决方案
您需要timeout
使用以下 --foreground
选项调用:
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
以关闭终端回声。我不知道为什么,但我想这与用于(不)收集用户密码的过程有关。(我只是在 strace 中看到它;我没有尝试找到调用。)尝试从后台进程更改 tty 配置将导致进程阻塞,直到它重新获得对 tty 的控制,这就是正在发生的事情。
不使用时不会发生,timeout
因为bash
不创建后台程序组。我想 fabric 2 避免调用tcsetattr
.
您也可以通过避免基于密码的 SSH 身份验证来避免该问题,但我没有尝试过。
您还可以通过重定向stdin
到/dev/null
(在timeout
命令中或在 shell 脚本的调用中)来避免该问题。如果您不需要将标准输入转发到远程命令(并且您可能不需要),那也可能是有用。
推荐阅读
- r - R中的纹理贴图
- openpyxl - Python Openpyxl 无法从第 6 列开始检查
- azure - 如何打开虚拟网关的 enableprivateipaddress 标志?
- android - 在 Flutter 中以 SPEAKER 模式进行直拨电话
- python - djnago-pytest 无法创建测试数据库
- sql - 唯一索引之上的 PostgreSQL Btree 索引
- oracle - 如何让 sql developer 正确显示变音符号而不是显示正方形?
- wordpress - WP 几个 meta_query 匹配,并重复计算
- python-3.x - 如何使用 Boto3 在 Windows EC2 实例中创建用户数据?
- unity3d - 如何根据来自不同脚本的变量缩放对象?