问题
问题 《Command line command to auto-kill a command after a certain amount of time》 中的回答提出了一种从 bash 命令行中为长时间运行的命令设置超时的方法:
( /path/to/slow command with options ) & sleep 5 ; kill $!
但是有可能某个“耗时长”的命令会早于超时时间完成执行。(我们可以戏称这类命令为“通常耗时长但有时运行快”的命令,简称 tlrbsf。)
所以这个巧妙的一行式方法存在几个问题。
首先,sleep
不具备条件性,这意味着它设定了整个流程所需的最低时间下限。设想一下,如果 tlrbsf
命令在 2 秒内就完成了,但我们却设定了 30 秒、2 分钟甚至是 5 分钟的 sleep
时间——这是非常不可取的。
其次,kill
命令的执行是无条件的,因此当该流程试图杀死一个已停止运行的进程时,会导致错误提示或警告信息。
是否存在一种方法能够在满足以下条件的情况下对通常耗时长但有时运行快(“tlrbsf”)的命令设置超时:
- 使用 bash 实现(其他问题已有 Perl 和 C 的答案)
- 当出现以下两种情况之一时终止:tlrbsf 命令执行完毕,或者超时时间到达
- 不会尝试杀死不存在或已停止的进程(可选条件:在杀死失败时不产生错误信息)
- 不强制要求是一行命令
- 可在 Cygwin 或 Linux 环境下运行
另外,若能实现以下加分项更好:
- 在前台运行 tlrbsf 命令
- 避免额外的后台睡眠进程或多余进程
使得 tlrbsf 命令的标准输入/标准输出/标准错误可以被重定向,就像直接运行该命令一样?
如果是,请分享你的代码。如果不是,请解释原因。
我已经花费一段时间试图改进上述示例,但现在似乎触及到了我 bash 技能的极限。
回答
你大概是在寻找 coreutils 中的 timeout
命令。尽管它本质上是一个 C 语言解决方案,因为它属于 coreutils 工具集的一部分。
timeout 5 /path/to/slow/command with options
这个命令是用来限制某个命令运行的时间的,其中:
timeout
: 这是一个 Linux 或类 Unix 系统自带的命令,用于限制其他命令的运行时间。5
: 这个数值指定了超时时间,单位是秒。在这例子里,如果/path/to/slow/command with options
这个命令在 5 秒钟之内没有结束运行,timeout
命令将会强制终止它。/path/to/slow/command
: 这是你要限制运行时间的命令的绝对路径,替换成实际的命令路径。with options
: 这部分是你想执行的具体命令的选项。
所以,整行命令的意思是:执行位于 /path/to/slow/command
位置的命令,并带上指定的选项,但如果该命令在 5 秒内未结束,就由 timeout
命令主动停止它。这样做的目的是防止命令无限制地运行,导致系统资源被长时间占用或其他问题。
笔者写了一个脚本 tlrbsf.sh
来充当提问者描述的 tlrbsf 命令,如下:
#! /usr/bin/bashcnt=$(($RANDOM % 7 + 2))
echo "count is $cnt"
ping -c $cnt www.baidu.com
其中 cnt
使用随机数来计算得出就模拟了 tlrbsf 命令每次运行所需时间不可提前预知这一条件。
在多次测试中,耗时长(大于超时时间)的情况如下:
耗时短的情况如下:
参考:
- stackoverflow question 687948
- man timeout
- man time
相关阅读:
- 2>&1是什么意思
- 如何用命令行将文本每两行合并为一行?
- 如何改变echo在Linux下的输出颜色
- 为什么要使用xargs命令
- Bash中 $! $* $@ 等各种符号的含义
- 在shell程序里如何从文件中获取第n行
如有疑问或者其他 Bash Shell 相关问题,欢迎在文末留言,你的独特视角,或许就是他人求解谜团的钥匙。