9

I'm trying to figure out more ways to see if a given host is up, solely using shell commands (primarily bash). Ideally, it would be able to work with both hostnames and IP addresses. Right now the only native way I know of is ping, perhaps integrated into a script as described here. Any other ideas?

7

ping is the way to test whether a host is alive and connected. (If a host is alive but disconnected or slow to respond, you can't distinguish that from its being dead.)

Options supported by the ping command vary from system to system. You'll want to ensure that it doesn't loop forever but returns after a few seconds if it didn't receive a reply.

With FreeBSD and Linux iputils, ping -c 1 -W 1 >/dev/null sends a single ping and wait 1 second. You don't need to parse the output: the command returns 0 if it received a ping back and nonzero otherwise (unknown host name, no route to host, no reply). Some implementations may need different flags (e.g. -w instead of -W on FreeBSD), check the manual on your system.

if ping -c 1 -W 1 "$hostname_or_ip_address"; then
  echo "$hostname_or_ip_address is alive"
else
  echo "$hostname_or_ip_address is pining for the fjords"
fi
  • I know it's the way, I was just hoping it wasn't the only way, even if the other ways are strange or fickle or what have you. Oh well! – user67459 Mar 18 '15 at 19:25
  • 2
    This answer should NOT have been marked as the answered answer. The OP specifically asked for more ways to see if a given host is up, other than with ping, which this answer does not supply. – Yokai Jan 21 '17 at 9:21
  • From 'ping' man page: "Because of the load it can impose on the network, it is unwise to use ping during normal operations or from automated scripts." – 1111161171159459134 Oct 26 '18 at 10:04
  • @1111161171159459134 That paragraph could have been worded better. It's overly alarmist. You shouldn't do flood pings or pings with a very high rate, but one ping packet now and then is negligible. – Gilles 'SO- stop being evil' Oct 26 '18 at 11:42
2

Ping is great to get a quick response about whether the host is connected to the network, but it often won't tell you whether the host is alive or not, or whether it's still operating as expected. This is because ping responses are usually handled by the kernel, so even if every application on the system has crashed (e.g. due to a disk failure or running out of memory), you'll often still get ping responses and may assume the machine is operating normally when the situation is quite the opposite.

Checking services

Usually you don't really care whether a host is still online or not, what you really care about is whether the machine is still performing some task. So if you can check the task directly then you'll know the host is both up and that the task is still running.

For a remote host that runs a web server for example, you can do something like this:

# Add the -f option to curl if server errors like HTTP 404 should fail too
if curl -I "http://$TARGET"; then
  echo "$TARGET alive and web site is up"
else
  echo "$TARGET offline or web server problem"
fi

If it runs SSH and you have keys set up for passwordless login, then you have a few more options, for example:

if ssh "$TARGET" true; then
  echo "$TARGET alive and accessible via SSH"
else
  echo "$TARGET offline or not accepting SSH logins"
fi

This works by SSH'ing into the host and running the true command and then closing the connection. The ssh command will only return success if that command could be run successfully.

Remote tests via SSH

You can extend this to check for specific processes, such as ensuring that mysqld is running on the machine:

if ssh "$TARGET" bash -c 'ps aux | grep -q mysqld'; then
  echo "$TARGET alive and running MySQL"
else
  echo "$TARGET offline or MySQL crashed"
fi

Of course in this case you'd be better off running something like monit on the target to ensure the service is kept running, but it's useful in scripts where you only want to perform some task on machine A as long as machine B is ready for it.

This could be something like checking that the target machine has a certain filesystem mounted before performing an rsync to it, so that you don't accidentally fill up its main disk if a secondary filesystem didn't mount for some reason. For example this will make sure that /mnt/raid is mounted on the target machine before continuing.

if ssh "$TARGET" bash -c 'mount | grep -q /mnt/raid'; then
  echo "$TARGET alive and filesystem ready to receive data"
else
  echo "$TARGET offline or filesystem not mounted"
fi

Services with no client

Sometimes there is no easy way to connect to the service and you just want to see whether it accepts incoming TCP connections, but when you telnet to the target on the port in question it just sits there and doesn't disconnect you, which means doing that in a script would cause it to hang.

While not quite so clean, you can still do this with the help of the timeout and netcat programs. For example this checks to see whether the machine accepts SMB/CIFS connections on TCP port 445, so you can see whether it is running Windows file sharing even if you don't have a password to log in, or the CIFS client tools aren't installed:

# Wait 1 second to connect (-w 1) and if the total time (DNS lookups + connect
# time) reaches 5 seconds, assume the connection was successful and the remote
# host is waiting for us to send data.  Connecting on TCP port 445.
if echo 'x' | timeout --preserve-status 5 nc -w 1 "$TARGET" 445; then
  echo "$TARGET alive and CIFS service available"
else
  echo "$TARGET offline or CIFS unavailable"
fi

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.