web-dev-qa-db-ja.com

スクリプトの継続的なpingループ

私はいくつかのカスタムOpenwrtコンパイルに取り組んでいます。スクリプトの中には、接続をテストする前にpingを実行して処理を行うものがあります。

if [ "$(ping -c 1 -w 3 8.8.8.8)" ]; then
  do stuff;
else
 echo "no connection"
fi

それらのいくつかは他のスクリプトを実行し、pingには時間がかかるため、スクリプトの実行に必要以上の時間がかかり、これが問題になる場合があります。

ファイルに0または1を書き込む連続ループのようなものを作りたいのですが。今後、接続テストにpingを使用するスクリプトは、somefileの内容をテストします。

そのようなスクリプトを書く方法はありますか?

3
180doman

あなたはこれほど簡単なことを意味しますか?

while :; do
   ping -c 1 -w 3 8.8.8.8; echo $? > /tmp/ping.status
   sleep 1
done

1秒に1回、pingの終了ステータスを/tmp/ping.statusに書き込みます。次に、別のスクリプトでは、次のようなものを使用できます。

pingFailed=$(cat /tmp/ping.status)
if [ $pingFailed -ne 0 ]; then
    echo "No connection"
else
    echo "Connected!"
fi

そう、あなたはこれを行うことができます。しかし、それはあなたの接続をチェックする本当に悪い方法です。明らかに、ここには競合状態があります。最初のループが実行されたときに接続がアクティブであったことは、この2番目のループがアクティブであったことを意味するものではありません。さらに重要なことは、スクリプトの最初にping.statusファイルを読んだとしても、接続がスクリプトの最後に残っているという意味ではありません。さらに、継続的なリクエストでネットワークとCPUの両方にスパムを送信しています。これは本当にエレガントではありません。

(少なくともLinuxで)接続が確立されているかどうかをテストするより速くて簡単な方法は、/sys/class/net/$NIC/link_modeを調べます。ここで、$NICはネットワークカードの名前です。たとえば、私のシステムでは:

## Wireless connection up
$ cat /sys/class/net/wlp3s0/link_mode 
1
## Wireless connection down
$ cat /sys/class/net/wlp3s0/link_mode 
0

これをチェックする関数を書くことができます:

isLinkDown(){
    return $(cat /sys/class/net/wlp3s0/link_mode)
}

また、次のようにスクリプトで使用できます。

if isLinkDown; then 
    echo Link Down
else
    echo Link Up
11
terdon

terdonの答えは良いですが、ネットワークの肥大化は避けます。

しかし、最初にaside; pingは0.002秒から8.8.8.8程度の時間がかかるため、低遅延ネットワークをテストする場合は、

$ timeout 0.1 ping -c 1 8.8.8.8

1/10秒のテスト時間を保証するために使用できます(pingには1秒未満の待ち時間がないため)。

今度はanswerで速度とネットワーク使用を最適化します。スクリプトにパラメータを渡させる必要があります。

#!/bin/bash

usage() {
    echo "Usage: $0 [OPTIONS]"
    echo " OPTIONS:"
    echo "  -h     this Help message"
    echo "  -n     do Not re-test network connectivity"
}

NO_TEST=false
while getopts "nh" OPT; do
    case "$OPT" in
        n)
            NO_TEST=true
            ;;
        h)
            usage
            exit 0
            ;;
        *)
            echo "unsupported option $OPT" >&2
            usage
            exit 1
            ;;
    esac
done
shift $((OPTIND - 1))

if ! $NO_TEST && ! ping -c 1 -w 3 8.8.8.8; then
    echo "no connection" >&2
    exit 2
fi
echo "do stuff";
3
user1133275

すべての回答をありがとうございました!私はあなたの貴重な考えのいくつかを考慮に入れるために少し時間が必要です。いくつかのことを明確にするために、私はそれを追加したいだけです:
1。これらのスクリプトのほとんどはinit.dで機能するか、cronで実行されるため、パラメーターを使用できません。
2。全体のアイデアは、主にモデム接続のために作成されています。また、pingの待機時間は信号強度に依存します。信号強度が低いときに信頼性の高いチェックを行うためにpingチェック間隔を1秒を超えて下げることはできますが、接続はまだ存在します。そのため、デフォルトの間隔でpingループを実行し、簡単にアクセスできる場所に結果を出力するだけでよいと考えました。

これは最近使用したものです

modemup(){
    echo -e "AT+QRST=1,0\r\n" > /dev/ttyUSB2
    ifdown $INTERFACE && ifup $INTERFACE

    if [ "$(ifconfig | grep $INTFC_NAME)" ]; then
        return 0
    else
        echo "Cant start modem interface"
        return 1
    fi
  } 

reconnect(){
    MAX_ATTEMPTS=$1 #number of tries before reboot
    TRIES=1

    while [ $TRIES -le $MAX_ATTEMPTS ]; do
        echo "Trying to reconnect ..."
        echo "Number of try: $TRIES"
        modemup
        /etc/init.d/network restart
        sleep 10
        if [ "$(ping -c 1 -w 3 8.8.8.8)" ]; then
            break
        fi
        : $((TRIES+=1))
    done
    echo "Tried $MAX_ATTEMPTS times, couldnt reconnect. Rebooting ..."
    reboot
}

while true; do
    if [ "$(ping -c 1 -w 3 8.8.8.8)" ]; then
         rm -rf $NOCONFILE #if noconnection file exists delete it
    else
        mkdir -p $LOG_DIR/${DAY_DIR}
        TIME=`date +%Y%m%d%H%M%S`
        echo "$TIME: Connection lost" 2>&1 | tee -a $LOG_FILE
        touch $NOCONFILE
        reconnect $ATTEMPTS 2>&1 | tee -a $LOG_FILE   
    fi
    sleep $INTERVAL
done
0
180doman