Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
shell中的时间条件循环_Shell - Fatal编程技术网

shell中的时间条件循环

shell中的时间条件循环,shell,Shell,我最近才开始学习shell脚本,所以对它了解不多 我试图找到基于时间的while循环的例子,但没有任何运气 我想运行一个特定时间的循环,比如说1小时。所以循环运行一个小时,然后自动结束 编辑:此循环将在没有任何睡眠的情况下连续运行,因此循环条件应基于循环的开始时间和当前时间,而不是睡眠时间。date+%s将为您提供自纪元以来的秒数,例如 startTime = `date +%s` timeSpan = #some number of seconds endTime = timeSpan + s

我最近才开始学习shell脚本,所以对它了解不多

我试图找到基于时间的while循环的例子,但没有任何运气

我想运行一个特定时间的循环,比如说1小时。所以循环运行一个小时,然后自动结束


编辑:此循环将在没有任何睡眠的情况下连续运行,因此循环条件应基于循环的开始时间和当前时间,而不是睡眠时间。

date+%s
将为您提供自纪元以来的秒数,例如

startTime = `date +%s`
timeSpan = #some number of seconds
endTime = timeSpan + startTime

while (( `date +%s` < endTime )) ; do
    #code
done
startTime=`date+%s`
timeSpan=#一些秒数
结束时间=时间跨度+开始时间
而(`date+%s`

您可能需要进行一些编辑,因为我的bash已经生锈了

最好的方法是使用$SECONDS变量,该变量包含脚本(或shell)运行的时间计数。下面的示例显示如何运行while循环3秒钟

#! /bin/bash
end=$((SECONDS+3))

while [ $SECONDS -lt $end ]; do
    # Do what you want.
    :
done

注意事项:此答案中的所有解决方案(除了
ksh
one)都可以提前1秒返回(但不包括),因为它们基于整数秒计数器,该计数器根据实时(系统)时钟而不是代码执行开始的时间前进


bash
ksh
zsh
解决方案,使用特殊的shell变量
$SECONDS
: 略为简化的@bsravanin答案

粗略地说,
$SECONDS
包含脚本中到目前为止经过的秒数

bash
zsh
中,您可以通过系统(实时)时钟的脉冲获得积分秒-即,幕后计数并非真正从
0
(!)开始,但是从一天中的最后一个完整时间开始,脚本恰好在秒开始,或者重置了
SECONDS
变量

相比之下,
ksh
的工作方式与人们预期的一样:当您重置
$SECONDS
时,计数真正开始于
0
;此外,
$SECONDS
报告
ksh
中的分数秒

因此,此解决方案可以合理预测和精确运行的唯一外壳是
ksh
。也就是说,对于粗略的测量和超时,它仍然可以在
bash
zsh
中使用

注意:下面使用了
bash
shebang行;只需将
ksh
zsh
替换为
bash
也将使脚本与这些shell一起运行

#!/usr/bin/env bash

secs=3600   # Set interval (duration) in seconds.

SECONDS=0   # Reset $SECONDS; counting of seconds will (re)start from 0(-ish).
while (( SECONDS < secs )); do    # Loop until interval has elapsed.
  # ...
done
你可以试试这个

starttime = `date +%s`
while [ $(( $(date +%s) - 3600 )) -lt $starttime ]; do
done

其中
'date+%s'
以秒为单位给出当前时间。

您可以浏览
日期的
-d
选项

下面是要举例说明的shell脚本片段。它与其他答案类似,但在不同的场景中可能更有用

# set -e to exit if the time provided by argument 1 is not valid for date.
# The variable stop_date will store the seconds since 1970-01-01 00:00:00
# UTC, according to the date specified by -d "$1".
set -e
stop_date=$(date -d "$1" "+%s")
set +e

echo -e "Starting at $(date)"
echo -e "Finishing at $(date -d "$1")"

# Repeat the loop while the current date is less than stop_date
while [ $(date "+%s") -lt ${stop_date} ]; do

    # your commands that will run until stop_date

done
然后,您可以用date理解的多种不同方式调用脚本:

$ ./the_script.sh "1 hour 4 minutes 3 seconds"
Starting at Fri Jun  2 10:50:28 BRT 2017
Finishing at Fri Jun  2 11:54:31 BRT 2017

$ ./the_script.sh "tomorrow 8:00am"
Starting at Fri Jun  2 10:50:39 BRT 2017
Finishing at Sat Jun  3 08:00:00 BRT 2017

$ ./the_script.sh "monday 8:00am"
Starting at Fri Jun  2 10:51:25 BRT 2017
Finishing at Mon Jun  5 08:00:00 BRT 2017

您可以使用可用的
循环
命令,如下所示:

$ loop './do_thing.sh' --for-duration 1h --every 5s

每五秒钟一次,持续一小时。这正是我想要的, 以下是一个基于bsravanin答案的单线解决方案:


结束=$((秒+30));of=$((结束秒));而[$SECONDS-lt$end];做回显$((结束秒))秒剩余的$of;睡眠1;完成

更现代的方法

猛击
declare-ir MAX_SECONDS=5
声明-ir超时=$SECONDS+$MAX_SECONDS
而($SECONDS<$TIMEOUT));做
#福
完成
科恩
typeset-ir MAX_SECONDS=5
排版-ir超时=$SECONDS+$MAX_SECONDS
而($SECONDS<$TIMEOUT));做
#酒吧
完成

bash和其他bourne shell变体都支持这一点,但我不确定它是否在POSIX规范中,因此您应该清楚地指定一个比
更具体的hash-bang shell/bin/sh
(这个答案的确如此,但我只是指出了它)。+1表示使用
$SECONDS
@RobStarling:它确实不是POSIX的一部分(请参阅我的答案,了解仅针对POSIX的解决方案);非详尽调查:
$SECONDS
适用于
bash
zsh
ksh
。在
ksh
中,它甚至会报告分数秒。这很有希望,但您的代码由于许多原因而中断;看我的答案。真的很好,但这不是一个标准:/
$ loop './do_thing.sh' --for-duration 1h --every 5s
declare -ir MAX_SECONDS=5
declare -ir TIMEOUT=$SECONDS+$MAX_SECONDS

while (( $SECONDS < $TIMEOUT )); do
    # foo
done
typeset -ir MAX_SECONDS=5
typeset -ir TIMEOUT=$SECONDS+$MAX_SECONDS

while (( $SECONDS < $TIMEOUT )); do
    # bar
done