每X秒执行一次命令


10

我希望每10秒执行一次命令,并使其在后台执行(因此消除了watch?)。所有答案均显示如下内容,但这将在11到14秒内执行。如何做到这一点?

while true; do
    # perform command that takes between 1 and 4 seconds
    sleep 10
done

也许带有实时信号。并正确处理leap秒。祝好运。
mikeserv

@mikeserv所以,不要打扰吗?我不在乎毫秒精度,只说半秒钟。
user1032531 2015年

你想达到什么目的?我发现必须以这种频率运行的任务通常是另一个问题的解决方法。
Sobrique

@Sobrique正是。我正在做一个轮询数据记录器的概念证明。实际上,将使用其他某种语言对其进行编程,但这目前仍然有效。
2015年

Answers:


16

怎么样:

( # In a subshell, for isolation, protecting $!
  while true; do
    perform-command & # in the background
    sleep 10 ;
    ### If you want to wait for a perform-command
    ### that happens to run for more than ten seconds,
    ### uncomment the following line:
    # wait $! ;
    ### If you prefer to kill a perform-command
    ### that happens to run for more than ten seconds,
    ### uncomment the following line instead:
    # kill $! ;
    ### (If you prefer to ignore it, uncomment neither.)
  done
)

ETA:有了所有这些注释,替代方案和提供额外保护的子外壳,看上去比起初要复杂得多。因此,为了进行比较,这是我开始担心waitor kill以及它们$!与隔离的需要之前的样子:

while true; do perform-command & sleep 10 ; done

其余的仅用于需要时。


您能否解释代码转储背后的原因?
伊斯梅尔·米格尔

2
另外,要引用您的代码适用于哪个shell(例如mikeserv的答案),以便当其他shell的行为有所不同时,人们不会感到困惑:)
ash

@IsmaelMiguel我认为这些评论可以解释其原因。我不确定还不清楚。
Sidhekin

1
bash手册说$!:“扩展到最近放置在后台的作业的进程ID”,而sleep不会放置在后台,因此不会。:)
Sidhekin

1
哇。在这两个方面都是错误的。什么时候发生的?
mikeserv 2015年

9

你可以这样做以下的bashzshksh

SECONDS=0
while   command
do      sleep "$((10-(SECONDS%10)))"
done

下面介绍一下bash手动说,有关$SECONDS

$SECONDS

  • 每次引用此参数时,返回自Shell调用以来的秒数。如果将值分配给$SECONDS,则后续引用返回的值是分配以来的秒数加上分配的值。如果$SECONDS为is unset,那么即使随后将其重置,它也会丢失其特殊属性。

这是一个工作示例:

(   SECONDS=0
    while   sleep   "$((RANDOM%10))"
    do      sleep   "$((10-(SECONDS%10)))"
            echo    "$SECONDS"
    done
)

10
20
30
40
50
60
70
80
90
100

2
为了避免重新SECONDSsleep "$((10-(($SECONDS-$start_time)%10)))"。您将需要start_time=$SECONDS在循环之前做。
ctrl-alt-delor

@richard-为什么要避免呢?
mikeserv

因为有一天,您将在一个这样的循环中将其保存在一个脚本中,您可以使用它来调用它。您会整天想知道为什么它无法正常工作。简而言之,如果您重置,它不会嵌套SECONDS。如在最新编辑中生成子外壳程序一样,也应该避免此问题。
ctrl-alt-delor

1
@richard-因为问题是关于while true循环的,所以我没有想到任何shell状态都可以生存。无论如何,在自己的上下文中包装这样的循环通常是最佳实践。在这种情况下,我会更担心这样做是出于缘故,trap而不是出于$SECONDS缘故。
mikeserv

谢谢Mike,我当时正在考虑做类似的事情(但还不知道具体如何做)。但是西德金的解决方案似乎做同样的事情,不是吗?我没有资格对更好的答案做出判断,但我有义务选择一些东西。
user1032531

3

仅BASH-您还可以计算命令花费的时间,并减去10:

TIMEFORMAT=$'%0R'
while true; do
    T=$({ time command; } 2>&1)
    sleep $(( 10-T ))

从BASH男子:

TIMEFORMAT此参数的值用作格式字符串,用于指定应如何显示带有时间保留字的管道的定时信息。%字符引入了转义序列,该序列被扩展为时间值或其他信息。转义序列及其含义如下:大括号表示可选部分。
%%文字%。
%[p] [l] R经过的时间(以秒为单位)。
%[p] [l] U用户模式下花费的CPU秒数。
%[p] [l] S在系统模式下花费的CPU秒数。
%P CPU百分比,计算为(%U +%S)/%R。

可选的p是一个数字,指定精度,即小数点后的小数位数。值0导致不输出小数点或小数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.