Shell Tricks: what to do when you can’t do internet

[Tweet]

Ok, so your home internet connection is down. Well, not right now, obviously. But your ISP has you on a waiting list for a service call, and you’re thinking you’ll just spend some time cleaning your office today. You’d love to know if your connection came back up in the meantime, though, right?

This trick is an evolution of one from OSXDaily. The idea is to just keep pinging a DNS server until we get a response, and then send an alert. For my working environment, I wanted something that would ensure I got the message.

Here’s the base function, imdown (I’m Down!):

# Wait for internet connection to come back up and notify
imdown() {
	until ping -W1 -c1 1.1.1.1; do
		sleep 10;
	done
	# notify somehow
}

I’m pinging the new 1.1.1.1 DNS Resolver. You could ping a website, but pinging the DNS resolver directly is faster. It won’t work if the connection problem is at the DNS level, but I’m only concerned with knowing when my modem is back online.

The ping command in this function uses 2 flags, -W1 and -c1. The -W is how long to wait for a response. We just want quick pings, so 1 second is enough. The -c1 is how many sweeps to do in a pass (with no -c it will just keep pinging forever), meaning we’ll just ping once and then sleep for 10 seconds before we try again. When it gets a successful ping, it moves on to the next step: notifying…

Insistent, nagging alerts

I made a really annoying loop for this. If the machine you’re running it on has sound, this is really effective. Assuming you’re around to shut it off, I suppose, because it would drive everyone else nuts and they’d end up smashing your speakers. But if you’re working around the house and want to know, turn up your volume and this will do the trick.

nag() {
	while true; do
		for phrase in "$@"; do
			afplay /System/Library/Sounds/Ping.aiff
			say -v Alex "$phrase"
			sleep 5
		done
	done
}

It takes one or more arguments, each being a quoted phrase to speak. It will enter into an infinite loop of playing a ding (the system “Ping” sound) and then speaking each phrase supplied to it (one at a time, in succession, or just one over and over if there’s only one argument) until you end it with CTRL-C.

Side note: If you want a female voice, changing say -v Alex to say -v Samantha works well. I miss the old voices… there used to be a bunch of funky voice modulations like “Bells” and creepy robot voices. Oh well.

So now my imdown function looks like this:

# Wait for internet connection to come back up and notify
imdown() {
	until ping -W1 -c1 8.8.8.8; do
		sleep 10;
	done
	nag \
	"internet connection is back up\!" \
	"Skynet is thinking" \
	"your tribulation is over, the internet is here" \
	"Praise what gods may be, we have internet\!" \
	"O M G we're online" \
	"In the words of Dr. Frankenstein, it's alive\!" \
	"rejoice, for the internet is risen"
}

It will cycle through these phrases, ad nauseam. It will get your attention, and those who share your space will hail you as a hero of great cleverness. That’s what those dirty looks mean, I swear.

Push It Real Good

If you have other means of getting notifications, such as a home automation system that can blink lights via script (I do :P), great. One option is to use Pushover, a free service that allows you to send push notifications to your iPhone (and Apple Watch) or Android device.

You can get various Pushover libraries for different languages, but it’s a really simple REST API, so you can just ping it from a script. Here’s how to set it up:

  • Create an account at Pushover
  • You’ll see your “User Key” prominently displayed after you log in. Copy that and save it
  • On your dashboard under “Your Applications”, click “Create an Application/API Token.” Just create one called “CLI”
  • Your application will get a token, copy that and save it, too

You’ll also need to install the Pushover app on your iOS or Android device for this to do much good.

Now, with your token and key in tow, you can ping the API. You could do it ugly with curl… the data needs to be passed as url encoded form data (percent encoded), like so (with your token and user key substituted in):

curl -X POST --form 'token=xxxxxxxxxxxxxxxx&user=xxxxxxxxxxxxxxxxx&title=Internet%20Connection%20Restored&message=Your%20internet%20connection%20is%20back%20online.&priority=1&sound=spacealarm' 'https://api.pushover.net/1/messages.json'

That would mean you could just create a bash function to send notifications. You can use this function to encode the strings:

# If you don't already have this in your bash profile
urlenc () { #url encode the passed string
	echo -n "$1" | perl -pe's/([^-_.~A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg'
}

pushnotify() {
	local token=xxxxxxxxxxxxxxxx
	local key=xxxxxxxxxxxxxxxx
	local formdata="token=${token}&user=${key}&title=$(urlenc $1)&message=$(urlenc $2)&priority=1&sound=spacealarm"
	curl -X POST -d $formdata 'https://api.pushover.net/1/messages.json'
}

Add something like pushnotify "Internet Connection" "Stop what you're doing, your internet connection is back up." to the imdown script (or replace the infinite loop of annoying voices entirely, but really, why limit yourself?).

Now you’ll get a notification on your phone and/or watch when your internet comes back up.

Here’s a gist with all the fun all in one place.

And here’s one that Alex Chan converted for Fish (with randomized phrase selection).

That was a lot of work for a minor convenience, I know. I happened to have all but the imdown function already in place, so really, I just did all the work for you. You’re welcome.

Ryan Irelan has produced a series of shell trick videos based on BrettTerpstra.com posts. Readers can get 10% off using the coupon code TERPSTRA.