Checking host availability by using ping in bash scripts
gives 1 no matter if I enter valid or invalid ip address. How can I check if a specific address (or better any of devices from list of ip addresses) went offline?
Not an answer to the question, but you’d better use «$(ping -c 1 some_ip_here)» instead of » ping -c 1 some_ip_here «. refer this link for more info
11 Answers 11
Ping returns different exit codes depending on the type of error.
ping 256.256.256.256 ; echo $? # 68 ping -c 1 127.0.0.1 ; echo $? # 0 ping -c 1 192.168.1.5 ; echo $? # 2
It does, your if will trigger the echo 1 block on any non-0 exit code (all errors). But to figure out what kind of error it was you will to check the exact exit code.
Do you get 68 on the first? I get 2 and unknow host. I get 1 on third example with Destination Host Unreachable.
I see the return code 68 on MacOS, but it is 2 on Linux for unresolvable hostname. There is also the -o option on MacOS (I assume in BSD also) which returns after a single successful packet.
You don’t need the backticks in the if statement. You can use this check
if ping -c 1 some_ip_here &> /dev/null then echo "success" else echo "error" fi
The if command checks the exit code of the following command (the ping). If the exit code is zero (which means that the command exited successfully) the then block will be executed. If it return a non-zero exit code, then the else block will be executed.
@TNT It depends on the shell. In bash &> file is equivalent to > file 2>&1 , i.e. redirects both standard output and and standard error.
I can think of a one liner like this to run
ping -c 1 127.0.0.1 &> /dev/null && echo success || echo fail
Replace 127.0.0.1 with IP or hostname, replace echo commands with what needs to be done in either case.
Code above will succeed, maybe try with an IP or hostname you know that is not accessible.
ping -c 1 google.com &> /dev/null && echo success || echo fail
ping -c 1 lolcatz.ninja &> /dev/null && echo success || echo fail
There is advanced version of ping — «fping», which gives possibility to define the timeout in milliseconds.
#!/bin/bash IP='192.168.1.1' fping -c1 -t300 $IP 2>/dev/null 1>/dev/null if [ "$?" = 0 ] then echo "Host found" else echo "Host not found" fi
In «unixy» ping -t isn’t for the timeout, but for the TTL. The timeout is specified via -W. Note: this can still block for a long time, eg. if the DNS server goes away and a DNS name has to be resolved. With the recent attacks in mind this should be considered.
Like many of the other answers here, this one has the antipattern cmd; if [ $? = 0 ]; then . which is better and more idiomatically written if cmd; then . — the purpose of if and the other flow control statements in the shell is precisely to run a command and check its exit status. You should very rarely need to examine $? directly.
This is a complete bash script which pings target every 5 seconds and logs errors to a file.
#!/bin/bash FILE=errors.txt TARGET=192.168.0.1 touch $FILE while true; do DATE=$(date '+%d/%m/%Y %H:%M:%S') ping -c 1 $TARGET &> /dev/null if [[ $? -ne 0 ]]; then echo "ERROR "$DATE echo $DATE >> $FILE else echo "OK "$DATE fi sleep 5 done
FYI, I just did some test using the method above and if we use multi ping (10 requests)
the result of multi ping command will be «0» if at least one of ping result reachable, and «1» in case where all ping requests are unreachable.
Send the output to a file in /tmp, check it from a GUI like lxpanel and you’ve got an up/down indicator for your tray. Or lately I’m into loops like ping every 30 seconds then sound a bell character and quit when a ping succeeds. Maybe with Termux on an Android phone. It ceases to be a one-liner though.
up=`fping -r 1 $1 ` if [ -z "$" ]; then printf "Host $1 not responding to ping \n" else printf "Host $1 responding to ping \n" fi
for i in `cat Hostlist` do ping -c1 -w2 $i | grep "PING" | awk '' done
This seems to work moderately well in a terminal emulator window. It loops until there’s a connection then stops.
#!/bin/bash # ping in a loop until the net is up declare -i s=0 declare -i m=0 while ! ping -c1 -w2 8.8.8.8 &> /dev/null ; do echo "down" $m:$s sleep 10 s=s+10 if test $s -ge 60; then s=0 m=m+1; fi done echo -e "--------->> UP! (connect a speaker)
The \a at the end is trying to get a bel char on connect. I've been trying to do this in LXDE/lxpanel but everything halts until I have a network connection again. Having a time started out as a progress indicator because if you look at a window with just "down" on every line you can't even tell it's moving.
Готовый скрипт проверки соединения с хостом (проверка инета или хоста)
Наткнулся на доработку, но конечного результата там не было. Выкладываю проверенный готовый скрипт:
#!/bin/bash # # Скрипт в бесконечном цикле пингует удалённый хост в инете с интервалом 5 сек # при первой удачной или неудачной попытке пинга пишется соответствующее сообщение в лог и на экран # следующая запись в лог делается только при изменении состояния связи # Узел опроса ip="ya.ru" # Кол-во пингов count=3 # инициализация переменной результата, по умолчанию считается, что связь уже есть status=connected # Файл логов logfile=/ping.log echo `date +%Y.%m.%d__%H:%M:%S`' Скрипт проверки связи запущен' >> $ # бесконечный цикл while [ true ]; do # пинг с последующей проверкой на ошибки result=$(ping -c $ $ 2<&1| grep -icE 'unknown|expired|unreachable|time out') # если ни один не прошел, то if [ "$status" = connected -a "$result" != 0 ]; then # Меняем статус, чтоб сообщение не повторялось до смены переменной result status=disconnected # Записываем в лог результат echo `date +%Y.%m.%d__%H:%M:%S`' Соединение с интернет отсутствует' >> $ # Вывод результата на экран echo `date +%Y.%m.%d__%H:%M:%S`' Соединение с интернет отсутствует' fi # если все пинги прошли, то if [ "$status" = disconnected -a "$result" -eq 0 ]; then # Меняем статус, чтоб сообщение не повторялось до смены переменной result status=connected # Пишем в лог время установки соединения echo `date +%Y.%m.%d__%H:%M:%S`' Связь есть' >> $ # Вывод результата на экран echo `date +%Y.%m.%d__%H:%M:%S`' Связь есть' fi # 5 сек задержка sleep 5 done
How can I check Internet access using a Bash script on Linux?
Personally, I enhance this pattern by making this wget -q --tries=10 --timeout=20 -O - http://google.com > /dev/null . That throws away the output, which means that files aren't left lying around, and there aren't any problems with write permissions.
You really should use --spider option as it will send a http HEAD request as opposed to a http GET request. Now, in this case you're checking against google.com which is a pretty light weight page so it may be ok as it is. But as a general rule you should use a HEAD request if you just want to check if something is available without actually downloading it. I've added to the answer accordingly.
If the school actually turns off their router instead of redirecting all traffic to a "why aren't you in bed" page, then there's no need to download an entire web page or send HTTP headers. All you have to do is just make a connection and check if someone's listening.
This will output "Connection to 8.8.8.8 port 53 [tcp/domain] succeeded!" and return a value of 0 if someone's listening.
If you want to use it in a shell script:
nc -z 8.8.8.8 53 >/dev/null 2>&1 online=$? if [ $online -eq 0 ]; then echo "Online" else echo "Offline" fi
This is the fastest approach, it pings the dns server instead of getting google's website data. thumbs up.
#!/bin/bash INTERNET_STATUS="UNKNOWN" TIMESTAMP=`date +%s` while [ 1 ] do ping -c 1 -W 0.7 8.8.4.4 > /dev/null 2>&1 if [ $? -eq 0 ] ; then if [ "$INTERNET_STATUS" != "UP" ]; then echo "UP `date +%Y-%m-%dT%H:%M:%S%Z` $((`date +%s`-$TIMESTAMP))"; INTERNET_STATUS="UP" fi else if [ "$INTERNET_STATUS" = "UP" ]; then echo "DOWN `date +%Y-%m-%dT%H:%M:%S%Z` $((`date +%s`-$TIMESTAMP))"; INTERNET_STATUS="DOWN" fi fi sleep 1 done;
The output will produce something like:
./internet_check.sh UP 2016-05-10T23:23:06BST 4 DOWN 2016-05-10T23:23:25BST 19 UP 2016-05-10T23:23:32BST 7
The number in the end of a line shows duration of previous state, i.e. 19 up, 7 seconds down.
Welcome to Stack Overflow! While this code may answer the question, it would be better to include some context, explaining how it works and when to use it. Code-only answers are not useful in the long run.
Had lots of ups and downs in a few minutes. While DropBox was online and surfing the web was possible. See unix.stackexchange.com/a/190610/19694 where they mention nc would be better to use than ping as quite a few hosters disable ICMP as well.
I fail to see how I would get the duration with the code above. I tried it and the 'duration' for each line grew monotonically. Doesn't TIMESTAMP have to be reset each time through the loop?
one problem with this solution is, that some networks might block outgoing pings (my uni had a famous record for doing so). it doesn't seem the be the case with the OP though.
Without wget
#!/bin/bash echo -e "GET http://google.com HTTP/1.0\n\n" | nc google.com 80 > /dev/null 2>&1 if [ $? -eq 0 ]; then echo "Online" else echo "Offline" fi
Install fping: > fewer problems than ping.
fping google.com | grep alive
#!/bin/bash itest=$(fping google.com | grep alive) while [ "$itest" == "" ] do sleep 5 itest=$(fping google.com | grep alive) done echo now online
Using the example above. I wrote this script to log the state of your connection: https://gist.github.com/cganterh/ffc2fffa8263857cbece
First, save the following code into a name.sh file.
#!/bin/bash while true do wget -q --tries=10 --timeout=20 -O - http://google.com > /dev/null if [[ $? -eq 0 ]]; then echo $(date) "1" | tee -a log.csv else echo $(date) "0" | tee -a log.csv fi sleep 5 done
Then, execute name.sh file in terminal, and then check the log state information in log.csv of the same folder.
I decided to combine a few of the previous answers, so I could later create a plot showing ups, downs, and their durations:
#!/bin/bash # # pinger is a bash shell script that monitors the network # status every 15 seconds and records if it is up '1' or down '0' # into the file log.csv from whence it may be plotted. # # author: J. W. Wooten, Ph.D. # since: 11/12/2019 # version: 1.0 # TIMESTAMP=`date +%s` while [ 1 ] do nc -z -w 5 8.8.8.8 53 >/dev/null 2>&1 online=$? TIME=`date +%s` if [ $online -eq 0 ]; then echo "`date +%Y-%m-%d_%H:%M:%S_%Z` 1 $(($TIME-$TIMESTAMP))" | tee -a log.csv else echo "`date +%Y-%m-%d_%H:%M:%S_%Z` 0 $(($TIME-$TIMESTAMP))" | tee -a log.csv fi TIMESTAMP=$TIME sleep 15 done;
This outputs to a CSV file every 15 seconds. Using Excel or Numbers, you can read the file and create a plot which will show when the Internet connection was not available and also the duration. If it changes from your sleep interval, then it is spending time trying to connect. I hope to add the ability to send me a text when it detects network is down next.