Как пинговать в linux, пока хост не известен?

46

Как я могу пинговать определенный адрес и, когда найден, перестать пинговать.

Я хочу использовать его в скрипте bash, поэтому, когда хост запускается, скрипт продолжает пинговать, и с момента доступности хоста скрипт продолжается ...

Сандер Верслуйс
источник

Ответы:

84

Дальнейшее упрощение ответа Мартины:

until ping -c1 www.google.com >/dev/null 2>&1; do :; done

обратите внимание, что сам ping используется в качестве проверки цикла; как только это удастся, цикл заканчивается. Тело цикла пустое, с нулевой командой " :", используемой для предотвращения синтаксической ошибки.

Обновление: я подумал о том, как заставить Control-C аккуратно выйти из цикла проверки связи. Это запустит цикл в фоновом режиме, перехватит сигнал прерывания (Control-C) и уничтожит фоновый цикл, если это произойдет:

ping_cancelled=false    # Keep track of whether the loop was cancelled, or succeeded
until ping -c1 "$1" >/dev/null 2>&1; do :; done &    # The "&" backgrounds it
trap "kill $!; ping_cancelled=true" SIGINT
wait $!          # Wait for the loop to exit, one way or another
trap - SIGINT    # Remove the trap, now we're done with it
echo "Done pinging, cancelled=$ping_cancelled"

Это немного сложновато, но если вы хотите, чтобы цикл был отменяемым, он должен сделать свое дело.

Гордон Дэвиссон
источник
6
Чтобы добавить «сон» (например, каждые 5 секунд): пока! ping -c1 www.google.com &> / dev / null; спать 5; сделано
Лепе
4
По умолчанию pingбудет ждать 10 секунд, прежде чем отказаться от своего пинга. Если вы хотите уменьшить это до 1 секунды, вы можете использовать -w1.
Джек О'Коннор
2
@ JackO'Connor Использование пинг BSD, это столица-W1
Люк Экстон
Моя единственная проблема с этим ответом - он плохо обрабатывает SIGINT. Вы не можете остановить это из командной строки, если по какой-либо причине он никогда не подключится.
Люк Экстон
@LukeExton Это связано с тем, как bash и ping обрабатывают SIGINT, и как они взаимодействуют (см. Этот вопрос ). У меня нет очень хорошего решения, но есть клочок: используйте Control-Z, чтобы остановить скрипт, а затем kill %1убить его.
Гордон Дэвиссон
25

Вы можете сделать цикл, отправить один пинг и в зависимости от статуса прервать цикл, например (bash):

while true; do ping -c1 www.google.com > /dev/null && break; done

Размещение этого где-то в вашем скрипте будет блокировать, пока не www.google.comстанет доступным

Святой Мартинас
источник
2
Это while trueи breakесть более чистое решение, ИМО.
Дэн Карли
1
@DanCarley Я собираюсь не согласиться с вами по той причине, что в принятом ответе, нулевой версии команды, можно заменить сон / ожидание, чтобы дать вашему ЦП перерыв, и в этом случае я бы назвал это более чистым решением. Другая проблема, связанная с этим ответом, заключается в том, что он требует от читателя / пользователя понять, как работает &&, и как, если первая команда не сработает, она не будет вызвана. Это просто мнение, как и ваше собственное.
Хамид
1
Основное различие, которое я вижу между этим решением и принятым, заключается в том, что оно будет отображать сообщение об ошибке «неизвестный хост ...» до тех пор, пока оно не будет найдено. Чтобы добавить сон (например, каждые 5 секунд):while true; do sleep 5; ping ...
Лепе
20

Я знаю, что вопрос старый ... и конкретно спрашивает относительно ping, но я хотел поделиться своим решением.

Я использую это при перезагрузке хостов, чтобы знать, когда я смогу снова подключиться к ним по SSH. (Так pingкак ответит за несколько секунд до sshdзапуска.)

until nc -vzw 2 $host 22; do sleep 2; done
Аарон Копли
источник
2
Это именно то, что я искал, спасибо! Вы даже можете прервать вызов с помощью CTRL + C, чего нельзя сказать о некоторых других решениях в этом потоке.
Алекс
1
Обратите внимание, что это работает для BSD-версий netcat. Версия nmap.org в дистрибутивах Linux реализована иначе, поэтому опция -z не существует, а опция -w ожидает подключения, но не закрывается при успешном завершении. Прекрасно работает в OSX, хотя.
Пол
Вот почему вы не останавливаетесь на первом (хорошем) ответе. Это ответ на реальную проблему.
Лев
11

Пингуйте целевой хост один раз. Проверьте, прошел ли пинг (возвращаемое значение пинга равно нулю). Если хост не жив, снова пропингуйте.

Следующий код можно сохранить в виде файла и вызвать с именем хоста в качестве аргумента или удалить из первой и последней строки и использовать в качестве функции в существующем сценарии (имя хоста waitForHost).

Код не оценивает причину сбоя, если эхо-запрос не приводит к ответу, таким образом, зацикливание навсегда, если хост не существует. Моя справочная страница BSD перечисляет значение каждого возвращаемого значения, в то время как linux нет, поэтому я думаю, что это не может быть переносимым, поэтому я и оставил его.

#!/bin/bash

PING=`which ping`

function waitForHost
{
    if [ -n "$1" ]; 
    then
        waitForHost1 $1;
    else
        echo "waitForHost: Hostname argument expected"
    fi
}

function waitForHost1
{
    reachable=0;
    while [ $reachable -eq 0 ];
    do
    $PING -q -c 1 $1
    if [ "$?" -eq 0 ];
    then
        reachable=1
    fi
    done
    sleep 5
}
waitForHost $1
Ян Юнгникель
источник
9
UNREACHEABLE=1;
while [ $UNREACHEABLE -ne "0" ]; 
   do ping -q -c 1 HOST &> /dev/null; UNREACHEABLE=$?; sleep 1;
done

Вы можете удалить сон 1, это только здесь, чтобы предотвратить любую проблему с переполнением в случае, когда хост будет повторно подключен, но ping не будет выходить с кодом 0.

радиус
источник
4

Пожалуйста, смотрите хорошие варианты в stackoverflow . Вот пример в bash, вам придется перебирать следующий код, пока он не вернет успешный результат проверки связи.


ping -c 1 -t 1 192.168.1.1;
if [ $? -eq 0 ]; then
    echo "192.168.1.1 is up";
else 
    echo "ip is down";
fi

Франсуа Вольмаранс
источник
3

Любой из вышеперечисленных циклов также можно использовать с fping, а не с ping, который, IMO, лучше подходит для использования в скриптах, чем сам ping. Смотрите fping (1) для деталей.

while ! fping -q $HOSTNAMES ; do :; done

также полезно для проверки работоспособности машин перед их выполнением. Простой пример:

для h в HOST1 HOST2 HOST3; делать
  если fping -q $ h; тогда
     echo -n "$ h:"
     ssh $ h "uname -a"
  фи
сделанный
саз
источник
1

Это будет пытаться определенное количество раз.

t=4; c=0; r=0; until ping -c 1 hostname.com >/dev/null 2>&1 || ((++c >= t)); do r=$?; done; echo $r

Вместо эха $rвы можете проверить его и действовать в соответствии с его значением:

if ((r)); then echo 'Failed to contact host'; else echo 'Continuing with script'; fi
Деннис Уильямсон
источник
1

Чтобы приятно обрабатывать SIGINT на пинг BSD.

HOST=google.com NO=1; while [ $NO -ne 0 ]; do ping -W1 -c1 $HOST &>/dev/null; NO=$?;echo "$(date) ($HOST) $NO" ; done; echo "$(date) ($HOST) reachable"

как функция

ping_until(){
  local NO=1
  while [ $NO -ne 0 ]; do
    ping -W1 -c1 $1 &>/dev/null; NO=$?
    # Optionally block ICMP flooding
    # sleep 1
    echo "$(date) ($1) ($NO)"
  done
}
Люк Экстон
источник
0

Я использовал следующую функцию. Мне это нравится, потому что я могу сказать, чтобы через некоторое время перестать пытаться:

#!/usr/bin/env bash

function networkup {
  # Initialize number of attempts
  reachable=$1
  while [ $reachable -ne 0 ]; do
    # Ping supplied host
    ping -q -c 1 -W 1 "$2" > /dev/null 2>&1
    # Check return code
    if [ $? -eq 0 ]; then
      # Success, we can exit with the right return code
      echo 0
      return
    fi
    # Network down, decrement counter and try again
    let reachable-=1
    # Sleep for one second
    sleep 1
  done
  # Network down, number of attempts exhausted, quiting
  echo 1
}

Его можно использовать для запуска чего-либо:

# Start-up a web browser, if network is up
if [ $(networkup 60 www.google.com) -eq 0 ]; then
  firefox &
fi
себя
источник
0

В общем, я хочу дождаться появления своей базы данных или другого сервера, но я не хочу ждать слишком долго. Следующий код ждет 10 секунд, а затем устанавливает код выхода, если сервер не появился в течение указанного времени.

Если сервер появится раньше установленного срока, цикл будет закорочен, чтобы можно было запустить следующий бит кода.

for i in `seq 1 10`; do date ; sleep 1 ; ping -c1 ${HOST} &>/dev/null && break ; done
johntellsall
источник
0

Дальнейшее улучшение ответа Гордона Дэвиссона:

until $(ping -c1 www.google.com &>/dev/null); do :; done

с окружающим '$ ()' запускается подоболочка, и поэтому вы можете использовать Control-C для завершения цикла в случае, если хост не станет доступным.

Шон  
источник