シェルスクリプトは1時間ファイルの可用性を確認し、1時間後にファイルが存在しない場合は「timeout」と表示されます。

シェルスクリプトは1時間ファイルの可用性を確認し、1時間後にファイルが存在しない場合は「timeout」と表示されます。

このコードを書いています。しかし、問題は、300秒ごとに$ fnameがループで終了すると、「Time over」が印刷されることです。ファイルが届かない場合は、1時間後に「タイムアウト」が必要ですが、300秒後に「タイムアウト」印刷が始まります。

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

ポーリングの欠点(短いポーリング周期のリソース消費と長いポーリング周期の変更検出待ち時間とのバランス)を防ぐ代替アプローチです。支払われた対価は、あなたがアクセスできないツールに依存することです。イノティファイツールそしてtimeout(後者は以下に由来する。GNU Coreutils)。

「可用性検証」は、ファイルが生成されるのを待っていることを意味すると仮定します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デフォルトの時間単位))の間にコマンドを実行します。タイムアウトに達するとtimeoutstatusで終了し124、それ以外の場合は実行中のコマンドの状態で終了します。

inotifywaitディレクトリ(dirディレクトリが作成されると予想されるディレクトリ)への変更を待つのは本当に静かです。$fnamecreate-qq

この確認は時々実装されます(たとえば、このサイトの他のQ&Aなど)。

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

ここで-m、(監視モード)はinotifywait最初の一致イベントの後に終了するのを防ぎ、パイプの右側はイベントに関連するファイルの名前を受け取ります。残念ながら、<newline>ファイル名にsが含まれている場合、この方法は機能しません。

そのため、上記のコードでは使用せずに存在するかどうかを2回-m確認してください。$fnameこのアプローチは少し脆弱です。$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

関連情報