1 時間ファイルの可用性をチェックするシェル スクリプト。1 時間経過してもファイルが存在しない場合は、「タイムアウト」と表示されます。

1 時間ファイルの可用性をチェックするシェル スクリプト。1 時間経過してもファイルが存在しない場合は、「タイムアウト」と表示されます。

このコードを書きました。しかし、問題は、$fname present がループから抜け出すと、300 秒ごとに「Time over」と表示されることです。ファイルが到着しない場合は 1 時間後に「time over」と表示したいのですが、300 秒後には「time over」と表示され始めます。

echo "enter file name"

read fname

START=`date +%s`
while [ $(( $(date +%s) - 3600 )) -lt $START ]; do
  if [ -e $fname ]
  then
    echo "$fname present"
    break
    sleep 300
  else
    echo "Time Over"
  fi
done

答え1

すでに完成に近づいていると思いますが、スクリプトの一部が複雑すぎるように見えます。

次のwhileループを試すことができます:

#!/bin/sh

timeout=3600
granularity=300
elapsed=0

echo "Please enter the filename"
read -r file

while [ "$elapsed" -lt "$timeout" ]
do
    if [ -f "$file" ]
    then
        break
    fi

    sleep "$granularity"
    elapsed=$((elapsed+granularity))
done

# Was the loop broken because the file appeared, or did it time out?
if [ -f "$file" ]
then
    echo "$file has appeared"
else
    echo "Time over"
fi

これは、値を超える$granularityまで、ファイルが存在するかどうかを毎秒チェックします。ファイルが存在する場合、スクリプトはループを抜けます。$timeout

あなたのアプローチの問題は、「時間超過」出力がelse定期チェックのブランチにあるため、ループが繰り返されるたびにファイルが見つからない場合は、代わりにループ後テスト変数 (スクリプトでは の出力date) が境界を超えた場合 (ループがタイムアウトしたことを示します)、または代わりに (おそらくさらに良い方法として) ファイルが存在する場合に、「時間超過」メッセージを出力するかどうかを決定します。

答え2

ポーリングの欠点(短いポーリングサイクルでのリソース消費と長いポーリングサイクルでの変更検出の遅延のトレードオフ)を回避する代替アプローチ。その代償として、利用できない可能性のあるツールに依存することになります。inotify ツールそしてtimeout(後者はGNU コアユーティリティ)。

「可用性を確認する」という意味が、ファイル(名前が変数内にあるfname)が作成されるのを待機することであると仮定します。

timeout 3600 sh -c '
    if [ -e "$1" ]; then
        printf "%s is present already\n" "$1"
        exit
    fi
    while inotifywait -qq -e create dir; do
    if [ -e "$1" ]; then
        printf "%s present\n" "$1"
        exit
    fi
done' mysh "$fname"
[ "$?" -eq 124 ] && echo "Time over"

timeout指定された期間、つまり秒数の間コマンドを実行します3600(sデフォルトの時間単位は )。タイムアウトに達すると、timeoutのステータスで終了します124。それ以外の場合は、実行中のコマンドのステータスで終了します。

inotifywaitディレクトリ (作成されるdirはずのディレクトリ)の変更を待機します。これは、監視しているイベントであり、非常に静かになります。$fnamecreate-qq

この種のチェックは、次のように実装されることがあります (たとえば、このサイトの他の Q/A など)。

inotifywait -m ... --format "%f" | while read -r file; do ...

where -m(モニター モード) は、inotifywait最初に一致するイベントの後に終了しないようにし、パイプの右側にはイベントの対象となるファイルの名前が渡されます。残念ながら、ファイル名に<newline>s が含まれている場合、この方法は機能しません。

そのため、上記のコードでは を使用せず、-mの存在を$fname2回確認しています。このアプローチは、$fname かもしれないの最初の[ -e "$1" ]実行と最初の実行の間inotifywait(および の実行の間も)に作成されます。 の実行ごとに独自の監視が設定されるinotifywaitため、監視対象ディレクトリに多数のファイルが作成された場合には、この方法は適していません。inotifywait

答え3

次のスクリプトはFILENAME、空の入力をチェックしながら読み取り、コマンドEND_DATEを使用して計算しdate、1 時間の実時間が超過していないことを確認し、指定されたファイルがFILENAME存在するかどうかを秒ごとにチェックしますINTERVAL。現在の日付の場合:

  • 等しい END_DATE: 最後にもう一度ファイルの存在チェックが行われ、スクリプトはすぐに while ループを終了します (300 秒待機する必要はありません)。
  • 超過 END_DATE: while ループはファイルの存在を確認せずに終了します。
#!/usr/bin/env bash

echo -n "Enter file name to monitor: "

read FILENAME

if [ -z "${FILENAME}" ]
then
    echo -e "\nError: Filename is empty!\nExiting..."
    exit 1
fi

END_DATE=$(date --date='next hour' '+%s')
INTERVAL=300

FOUND="false"
while :
do
    CURRENT_DATE="$(date '+%s')"
    if [ "${CURRENT_DATE}" -gt "${END_DATE}" ]
    then
        break
    elif [ "${CURRENT_DATE}" -eq "${END_DATE}" ]
    then
        INTERVAL='0.1'   # Allow for one last check
    fi

    if [ -e "${FILENAME}" ]
    then
        FOUND="true"
        break
    fi
    sleep "${INTERVAL}"
done

if [ "${FOUND}" == "true" ]
then
    echo "${FILENAME} is present"
else
    echo "Time is Over"
fi

関連情報