30.03.2016Быстрый пинг
Предисловие
Сегодня хочу рассказать про чтение мануалов. Например, с их помощью я выяснил, что чтобы разрабатывать баш-скрипты на маке (он у меня не так давно) под линукс, нужно ставить coreutils. Потому что команды терминала ведут себя по-разному, имеют разные доступные опции и разные дефолтные настройки.
Баш мне вообще очень нравится. Я его довольно плохо знаю, он очень древний и немного уродливый, но даёт совершенно ни с чем не сравнимое удовольствие и чувство гордости, когда получается сделать что-то полезное на нём.
Задача
Очень многие, даже независимо от системы, пользовались командой терминала ping. Она позволяет быстро и наглядно определить, есть ли связь с тем или иным узлом. Передо мной встала задача, чтобы определял наличие связи с узлом скрипт, а не человек с глазами. Нужно было быстро и дёшево получить однозначный ответ в виде кода завершения. Что же, открываем
man ping
Ход решения
- Линуксовый пинг продолжается бесконечно, поэтому нужно ограничить число пакетов. Опция -с.
- Можно сделать пакет меньше с помощью опции -s.
- Можно уменьшить интервал между посылаемыми пакетами (но не меньше 0.2 секунд, если пингует не суперпользователь) с помощью опции -i.
- Или же интервал можно сделать адаптивным, чтобы он сам ускорялся, если ответ пришёл быстро с помощью -A.
- можно не выводить ненужную нашему скрипту информацию с помощью -q и перенаправить стандартный вывод ошибок в никуда.
Что мы получили:
$ ping -A -s16 -c3 -q ya.ru 2>/dev/null
PING ya.ru (93.158.134.3) 16(44) bytes of data.
--- ya.ru ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 400ms
rtt min/avg/max/mdev = 1.923/2.075/2.339/0.187 ms, ipg/ewma 200.281/1.973 ms
Пока всё ещё многовато читать. Хорошо бы вытащить только число полученных пакетов. А оно у нас как раз после первой запятой в строчке рядом со словом «received».
$ ping -A -s16 -c3 -q ya.ru 2>/dev/null | grep received
3 packets transmitted, 3 received, 0% packet loss, time 401ms
$ ping -A -s16 -c3 -q ya.ru 2>/dev/null | grep received | awk -F', ' '{print $2}'
3 received
$ ping -A -s16 -c3 -q ya.ru 2>/dev/null | grep received | awk -F', ' '{print $2}' | awk '{print $1}'
3
Почти всё работает быстро, кроме выключенных машин и несуществующих адресов (не имён). В отличие от ошибки DNS пинг требует убедиться, что всё действительно недоступно. Но мне нужно быстро и однозначно. Повезло, что плохое соединение для моей задачи равносильно отсутствию соединения. На помощь приходит timeout:
$ timeout 1 ping -A -s16 -c3 -q ya.ru 2>/dev/null
Теперь нужно передавать фейл дальше и сверять, собственно, число пингов. Получаем наш красивенький быстрый fastping.sh:
#!/bin/bash
cnt=3
to=1
rcvd=$(set -o pipefail; timeout $to ping -A -s16 -c$cnt -q $1 2> /dev/null | grep received | awk -F', ' '{print $2}' | awk '{print $1}')
if [[ $? != 0 || $cnt != $rcvd ]]; then
exit 1
fi
Дополнительно
- man ping
- Полная версия fastping.sh, в которой можно задать число пакетов и таймаут, но они имеют дефолтные значения.
- Пинг на стероидах — fping.