53

I have just started learning shell script recently, so I don't know much about it.

I am trying to find example of time based while loop but not having any luck.

I want to run a loop for specific amount of time, let's say 1 hour. So loop runs for an hour and then ends automatically.

Edit: This loop will run continiously without any sleep, so the loop condition should be based on loop's start time and current time, not on sleep.

4

8 に答える 8

107

これを行う最良の方法は、スクリプト(またはシェル)が実行されていた時間のカウントを持つ$SECONDS変数を使用することです。以下のサンプルは、whileループを3秒間実行する方法を示しています。

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

while [ $SECONDS -lt $end ]; do
    # Do what you want.
    :
done
于 2012-06-25T23:12:59.213 に答える
31

警告:この回答のすべてのソリューション(1つを除く)は、リアルタイム(システム)クロックに基づいて進む整数秒カウンターに基づいているため、1秒早くksh戻ることができます(ただし、含まれていません)。コードの実行がいつ開始されたかに基づきます。


bash、、ソリューションkshzsh特別なシェル変数を使用$SECONDS

@bsravaninの答えの少し簡略化されたバージョン。

大まかに言えば、$SECONDSスクリプトでこれまでに経過した秒数が含まれます。

bashで、システム(リアルタイム)クロックのパルスによって整数zsh秒が進みます。つまり、舞台裏でのカウントは実際には(!)から始まりませんが、最後のフルタイム秒以降のどの部分でもスクリプトがたまたま開始されたか、変数がリセットされました。0SECONDS

対照的に、期待どおりに動作します。実際には、リセットしたときにkshカウントが開始されます。さらに、で小数秒を報告します。0$SECONDS$SECONDSksh

したがって、このソリューションが合理的に予測可能かつ正確に機能する唯一のシェルはですksh。とは言うものの大まかな測定とタイムアウトの場合は、とでまだ使用できる可能性がbashありzshます。

注:以下はbashシバンラインを使用しています。kshまたはzshを置き換えるだけbashで、これらのシェルでもスクリプトが実行されます。

#!/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

Ubuntuの()shなどのPOSIX機能のみのシェルのソリューション( POSIXに準拠していません)dash$SECONDS

@dcpomeroの回答のクリーンアップバージョン。

によって返されるエポック時間date +%s(1970年1月1日から経過した秒数)と条件付きのPOSIX構文を使用します。

警告date +%sそれ自体(具体的には%sフォーマット)はPOSIXに準拠していませんが、(少なくとも)Linux、FreeBSD、およびOSXで動作します。

#!/bin/sh

secs=3600                         # Set interval (duration) in seconds.
endTime=$(( $(date +%s) + secs )) # Calculate end time.

while [ $(date +%s) -lt $endTime ]; do  # Loop until interval has elapsed.
    # ...
done
于 2014-03-29T19:23:13.283 に答える
2

あなたはこれを試すことができます

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

ここで'date +%s'、現在の時刻を秒単位で示します。

于 2015-01-16T06:31:04.013 に答える
1

date +%sエポックからの秒数が表示されるので、

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

while (( `date +%s` < endTime )) ; do
    #code
done

私のbashは錆びているので、編集が必要な場合があります

于 2012-06-25T22:51:24.667 に答える
1

-dのオプションを調べることができますdate

以下は、例示するシェルスクリプトスニペットです。他の回答と似ていますが、さまざまなシナリオで役立つ場合があります。

# 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
于 2017-06-02T15:45:29.997 に答える
1

次のように、ここで使用できるloopコマンドを使用できます。

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

これは、5秒ごとに1時間あなたのことをします。

于 2018-06-26T20:38:45.853 に答える
1

これはまさに私が探していたものです。これがbsravaninの答えに基づく1行のソリューションです。

end = $((SECONDS + 30)); of = $((end-SECONDS)); while [$ SECONDS -lt $ end]; $ ofの残りの$((end-SECONDS))秒をエコーし​​ます; 睡眠1; 終わり;

于 2018-09-13T10:58:54.510 に答える
0

より現代的なアプローチのために...

バッシュ

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
于 2020-03-02T10:26:14.203 に答える