让命令运行 5 分钟的简单方法是什么?

让命令运行 5 分钟的简单方法是什么?

有没有一种简单的方法可以让特定命令(只能通过终止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)       |
\-----------------------------+------------+----------------/

笔记:

  1. timeout总是用作SIGKILL最后的手段信号。
  2. 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 之间真正的区别在于dashcshbashtcshzsh
内置命令read[2]和选项-t。在第一个版本中,如果用户在指定的秒数之前未完成一行输入,则该指令将终止并生成错误返回代码。

-t 超时 如果在 TIMEOUT 秒内未读取完整行输入,则导致读取超时并返回失败。

第二个版本与第一个版本一样,但您可以按 来中止终止超时enter
实际上,或运算符仅在命令以非零的返回代码退出时(例如超时已过期)才||执行语句。如果您在此之前按下 ,它将返回 0 并且不会终止您的上一个命令。killreadenter


Coreutils 解决方案[1]

什么时候核心工具存在于您的系统中,您无需节省时间和资源来调用外部程序, timeout并且sleep和都是实现您的目标的完美方式。

timeout的使用timeout很简单。
最后,您还可以考虑使用-k在第一个失败时发送附加终止信号的选项。

timeout 5m YourCommand                                         # 3rd version 

sleepsleep可以利用你的幻想或从中得到一些灵感[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,只在真正需要的时候使用。

参考

  • [1] Coreutils
  • [2] Bash 初学者指南
  • [3] Bash常见问题

答案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}"。此外,总是将位置参数放在双引号内。

相关内容