有没有一种简单的方法可以让特定命令(只能通过终止Ctrl-C
)自动运行 5 分钟?
例如:
minute-command 5-minutes ping www.google.com
或任何其他不会自行终止的命令。
我希望能够指定一个时间限制,而不仅仅是 5 分钟。
答案1
至少有两个程序提供此功能:
姓名
timelimit
— 有效限制进程的绝对执行时间概要
timelimit [-pq] [-S killsig] [-s warnsig] [-T killtime] [-t warntime] command [arguments ...]
和
姓名
timeout
- 运行带有时间限制的命令概要
timeout [OPTION] DURATION COMMAND [ARG]...
timeout [OPTION]
它们的包装如下:
$ dlocate `which timeout timelimit`
timelimit: /usr/bin/timelimit
coreutils: /usr/bin/timeout
比较:
/-----------------------------+------------+----------------\
| Feature | timelimit | timeout |
+=============================+============+================+
| time to run | -t time | first argument |
+-----------------------------+------------+----------------+
| terminate signal | -s signal | -s signal |
+-----------------------------+------------+----------------+
| grace period | -T time | -k time |
+-----------------------------+------------+----------------+
| kill signal | -S signal | (note 1) |
+-----------------------------+------------+----------------+
| propagate signals | -p | (note 2) |
\-----------------------------+------------+----------------/
笔记:
timeout
总是用作SIGKILL
最后的手段信号。timeout
当子程序退出时,没有任何通过信号退出的功能。
这两个程序的退出状态不同,但很难清楚地总结,所以我建议你自己查阅手册页。
由于timeout
默认情况下在更多系统上安装(coreutils
是许多发行版中的标准包),我建议您使用它,除非您需要提供的额外功能timelimit
。
答案2
事实上,这是timeout
为了:
TIMEOUT(1) User Commands TIMEOUT(1)
NAME
timeout - run a command with a time limit
SYNOPSIS
timeout [OPTION] DURATION COMMAND [ARG]...
timeout [OPTION]
DESCRIPTION
Start COMMAND, and kill it if still running after DURATION.
lx@lxtp:~$ dpkg -S /usr/bin/timeout
coreutils: /usr/bin/timeout
答案3
纯bash
内置,无核心工具
我发现这个解决方案依赖bash
于内置命令,而无需调用外部可执行文件。它适用于最终甚至没有安装的系统核心工具 [1]
YourCommand & read -t 300 ; kill $! # 1st version
YourCommand & read -t 300 || kill $! # 2nd version
解释:通常,当您使用 发送后台命令时&
,其 PID 会存储在内部变量中(存在于、、、、...$!
的现代版本中)。shell 之间真正的区别在于dash
csh
bash
tcsh
zsh
内置命令read
[2]和选项-t
。在第一个版本中,如果用户在指定的秒数之前未完成一行输入,则该指令将终止并生成错误返回代码。
-t 超时 如果在 TIMEOUT 秒内未读取完整行输入,则导致读取超时并返回失败。
第二个版本与第一个版本一样,但您可以按 来中止终止超时enter。
实际上,或运算符仅在命令以非零的返回代码退出时(例如超时已过期)才||
执行语句。如果您在此之前按下 ,它将返回 0 并且不会终止您的上一个命令。kill
read
enter
Coreutils 解决方案[1]
什么时候核心工具存在于您的系统中,您无需节省时间和资源来调用外部程序, timeout
并且sleep
和都是实现您的目标的完美方式。
timeout
的使用timeout
很简单。
最后,您还可以考虑使用-k
在第一个失败时发送附加终止信号的选项。
timeout 5m YourCommand # 3rd version
sleep
你sleep
可以利用你的幻想或从中得到一些灵感[3]。请注意,您可以将命令留在后台或前台(例如,top
通常需要在前台)。
YourCommand & sleep 5m; kill $! # 4th Background
YourCommand & pid=$! ; (sleep 5m; kill $pid;) & # 5th Background
bash -c '(sleep 5m; kill $$) & exec YourCommand' # 6th Foreground
(cmdpid=$BASHPID; (sleep 5m; kill $cmdpid) & exec YourCommand) # 7th Foreground
解释
- 在第 4 版中,您在后台执行,
YourCommand
然后您的 shellsleep
会运行 5 分钟。当它完成后,最后一个后台进程 ($!
) 将被终止。您停止 shell。 -
在第 5 版中,您可以在后台执行
YourCommand
,并立即将该 PID 存储在变量中$pid
。然后,您可以在后台执行小憩5 分钟,其后续命令将终止存储的 PID。由于您在后台发送了这组命令,因此您不会停止 shell。您需要将 PID 存储在变量中,因为 的值$!
可能会被后台另一个程序的最终执行所更新。简而言之,您避免了杀错误的流程或者根本没有流程。 - 在第 6 版中,它被称为新的 bash shell,它将在 5 分钟内通过以下方式自杀:
$$
,然后它会执行留在前台的命令。 - 在第 7 版中,它调用一个子 shell
()
,将其 PID 存储在变量 (cmdpid
) 中,并使用在后台执行中发送的另一个子 shell 终止自身,然后在前台运行 YourCommand。
当然,在每个版本中你都可以发送你需要的终止信号,从默认信号到极端 kill -9
,只在真正需要的时候使用。
参考
答案4
您可以使用如下简单的脚本来完成此操作:
#!/bin/bash
#
# $1 is the time to let the program run, and $2, $3, ... are the command itself.
#
"${@:2}" &
PID=$!
sleep "${@:1:1}"
kill -2 $PID
(信号 SIGINT=2 按照下面评论中 Matija Nalis 的建议使用)。
对 (不常见的?) bash 表达式的解释$@:...
:位置参数 ( $*, $@, "$*", "$@"
) 允许以下额外规范,例如:
"${@:START:COUNT}"
意思是:在所有参数中,取 COUNT 个,第一个要取的是位于 START 位置的参数;如果省略 COUNT,则从 START 位置开始取所有参数直到末尾。请记住这$0
是程序名称。如果 START 为负数,则从末尾开始计数,并记住 COUNT不能为负数,因此最后一个参数是"${@:-1}"
。此外,总是将位置参数放在双引号内。