All posts by ThatBlairGuy

That Blair Guy has been working in software for longer than he cares to admit. These days he works throughout the software stack from the web UI down to SQL (and sometimes no-SQL), mostly on the .Net framework, but with occasional excursions to Linux.

Finding Your Router’s Public IP Address

It’s easy enough to find your home router’s public facing IP address (the one your ISP assigns) via a Google search; they even make it the first result on the page. But what if you want to find it via a script?

That’s the challenge I’m trying to solve. What’s more, I want to do this without calling something on an external service. I’ll only be looking it up once every five minutes or so, but I’d prefer to not be a nuisance. (And if something goes wrong and my script runs in a tight loop, I’d rather not have the polling hammer someone else’s server.)

I found a script on the Linux & Things blog which almost does what I want. That script doesn’t quite work for me though, my route command doesn’t flag the default gateway.

But that’s OK, the bulk of what that script does is to look up the local network’s name for the router. That’s a nice bit of robustness, just in case the router’s name does change for some reason (e.g. switching from Fios to Comcast, you’d get a new router and the new router would likely have a different default name). But for my purposes, it’s good enough to know that the router’s name is always going to be Fred. (No, not really, that would be silly. My router’s real name is Ethel.)

So from a bash prompt, we end up with this snippet of code:

external_address=$(nslookup Fred.home | grep Address | tail -1 | awk ‘{print $2}’)

That one-liner really breaks down to five parts.

nslookup Fred.home looks up Fred’s entry in the local DNS. What I get is something similar to:


Name: Fred.home
Name: Fred.home

Now none of that’s my real network information, but what we’re after is that last “Address” line.

Piping the output of nslookup through grep Address throws away every line which doesn’t contain the word “Address”, leaving this:


Getting closer, next, it gets piped through tail -1 which grabs just the last line:


Excellent! That’s almost what we want.

The next step in the chain is to run it through awk '{print $2}' which uses the AWK tool to output just the second token in the stream.

Finally, the entire thing is wrapped in the $() operator, which captures the output of those four steps and allows us to assign them to the


variable, which allows the external address to be used elsewhere:

external_address=$(nslookup Fred.home | grep Address | tail -1 | awk ‘{print $2}’)
echo $external_address

This (obviously) runs at a bash prompt. I’ve tried it out on Ubuntu and the Windows Subsystem for Linux, though I can’t imagine it wouldn’t work on other distributions as well. Most of the magic in this is text parsing. The Windows version of nslookup provides similar output, just formatted differently; there’s no reason a PowerShell script couldn’t do some similar processing to find the address.

Rubber Duck Debugging

A co-worker asked me a question relating to how our software works. As soon as he finished framing the question, and before I could respond, he finished with, “Oh, of course…” and answered his own question. I don’t there’s a techie alive who hasn’t experienced this phenomenon from one side or the other.

There’s a practice called “Rubber Duck Debugging.” In a nutshell, when you have a problem, you explain the problem to the duck so that you can figure it out.

Coincidentally, there’s a rubber duck on top of a bookcase next to my desk. This co-worker and I had gone through similar debugging episodes before, so I told him that going forward, he should first talk to the duck. This particular co-worker works remotely most of the week, so I told him we’d have to find a way he could talk to the duck online.

Sure enough, someone else had already thought of this. Five minutes later, I found the Cyberduck – an Eliza-based chatbot.

Two Git bookmarks

I follow Mark Hamill on Twitter because I find him entertaining. For example, this exchange:

On the other hand, I primarily follow Scott Hanselman because he drops interesting tech nuggets, such as when he retweeted this:

Don’t get me wrong, Scott can be entertaining too, but the git config linked from that tweet is full of things I didn’t even know you could configure! (Six months in, I’m still finding entirely new realms within git that I didn’t realize I didn’t know about!)

Seeing the config sections for the merge and diff tools, I also verified that yes, the bc merge/diff tool referenced in the git documentation really is (or at least, can be) Beyond Compare. I’ve been using TortiseGit for my Git GUI needs, but I also like Beyond Compare. (The default vi-based diff tool is just painful.)

And then I find an article about how to configure Beyond Compare to work with Git.

Two New Commands

I enjoy learning new things. When I do, I’ll try to write them down in case others may perhaps also find them useful. If nothing else, the notes may help me when I’m wondering, “How did this get solved last time?”

My team at work is in the process of switch from Subversion to Git and GitHub. Git is new ground for many of us, as is the bash prompt (On Windows, Git includes a full-fledged bash prompt). Doing some troubleshooting today, I learned some new new things about both tools.

Pretty git logs

The first was a new Git command:
 git log --graph --oneline

This creates a wonderful ASCII-art timeline, showing all your commits and showing how files have been merged into the project.

For a project of any complexity, this simple visualization is wonderful for understanding the flow of changes and merges by multiple developers. Check out this snippet from PhantomCSS for example:

[email protected] MINGW64 ~/test
$ git log --graph --oneline
* 20db940 0.10.4
* a482cc3 Merge pull request #127 from raveclassic/master
| * bbbaa22 fixed TypeError when calling phantomcss.compareAll() #68
* | e44196e Merge pull request #125 from shadowfiles/extension-settings
|\ \
| * | 28a397f Added option to specify the suffix names of screenshot types.
| |/
* | d8479cf Merge pull request #124 from renanborgez/patch-1
|\ \
| |/
| * 4b0913f Update
* 84945e5 0.10.2


Commit 4b0913f (near the bottom) updates the and is then meged back in commit d8479cf.  Meanwhile, a separate developer is adding new functionality in commit 28a397f, merges two pull requests in commits e44196e and bbbaa22 before everything comes back together in a482cc3

It’s a bit cryptic at first, but much easier to fathom than the straight up git log.

The same format also appears, in a non-text based format, in the gitk tool.

A new (to me) bash command

The other new command was from bash. I’ve known for a while that your command line history is stored in ~/.bash_history, but I didn’t know what it was good for aside from presumably powering the up-arrow / down arrow line-at-a-time history.

Turns out that the history command also displays your command line history, and it’s waaaaay more convenient than typing
more < ~/.bash_history
As a bonus, if you have multiple terminals open, this command is guaranteed to show the history for the current window rather than the one most recently closed.

Princess Leia’s Stolen Death Star Plans

In 1967, The Beatles ‏released the album “Sgt. Pepper’s Lonley Hearts Club Band.”
In 1977, Star Wars opened.
In 2017, the band Palette-Swap Ninja, released a mash up of the two.

Some of the tracks don’t do much for me. For example, although the lyrics are moderately clever, “Luke is in the desert, whining” just hits me as a boring bit of music. (The original Lucy in the Sky with Diamonds hits me about the same way.)

On the other hand, some of the other tracks are downright brilliant. I particularly like the way they managed to work some of the original music, for example the cantina band in “Being From the Spaceport of Mos Eisley.”

And if that wasn’t enough, they also put together a YouTube playlist to go with it so you can see watch story unfold and read (and sing) along with the lyrics.

(Image credit: Palette-Swap Ninja)

Cabal and Other Irresponsible Invocations of The Muse

Writer-pal Michael Jan Friedman is in the final days of a KickStarter campaign for a new book titled Cabal and Other Irresponsible Invocations of The Muse.

From the descriptions, it sounds like a fun assortment of Science Fiction and Fantasy. There’s one story, which defies classification (Mike says it belongs in every section of the bookstore): it’s a police procedural set in an alternate universe, modern-day, Aztec empire, and features a detective named Maxtla Colhua — the very same character whom Maxtla is named for.

If any of this intrigues you, please do check out his KickStarter campaign. I’d really like to read this.

(Image via MichaelJanFriedman.Net)

Protecting Your Online Data

Advertisement for Norton VPN Dad forwarded an email he got from Symantec today. The subject line was “Breaking: New legislation affects your online privacy” and went on to suggest he could subscribe to their “Norton WiFi Privacy” product to stop his Internet Service Provider from selling his browsing data.

My take is that he should save his money. This is just Symantec doing some very opportunistic, and cynical, marketing. The place where a VPN is most valuable is when you’re using a network you don’t know whether to trust (e.g. the free WiFi at your neighborhood sub shop).

For now at least, Comcast, Verizon, AT&T and probably others are making a big deal about how they’re not collecting/selling your web browsing behavior (though they’re certainly leaving room to change that once the furor dies down — they did after all spend a huge amount of money lobbying against those rules).

Even without VPN, when you visit a web site that uses HTTPS (and more than half of the web does now), your internet provider can’t tell what you did there. They can certainly tell that you visited, but because it’s https:// instead of http://, they can’t tell what specific pages you visited.

USA Today had a good article about some ways to protect your online privacy. Subscribing to a VPN service wasn’t one of them.

String Types

Not quite a year ago, I received a .Net Rocks! mug from Richard Campbell and Carl Franklin after a comment I’d left for a previous episode was read on the show. History repeated itself on Thursday when they used another of my comments, this time one about C++, as the lead-in for the show’s main topic.

Thursday’s show was about a scripting language, chaiscript, that allows you to write scripts in C++ and use them from other C++ projects. (C++ as a scripting language is a neat trick since it’s normally compiled ahead of time and shipped to the user as a binary executable.) It’s an interesting show and you should absolutely give it a listen. There’s also an interesting bit around the 20 mark, talking about the Commodore 64 (I had no idea those disk drives had CPUs).

The gist of my comment was that some of the features added to C++ since I’d last used it sounded rather compelling (particularly “stack semantics” which sound like there’s a sharply reduced need for new and delete, and that even pointers are largely hidden). I still have reservations though because of “scars from working with a half-dozen different, not-quite compatible string types.”

The first web application I ever worked on was a bit of a brownfield product, sharing code for the business logic with a desktop product that used the Microsoft Foundation Classes library (MFC). The resulting web application started off with char * along with the MFC CString class. (That’s two string types right there.)

Because this application ran on Active Server Pages (so-called “Classic ASP”), we soon added the BSTR and CComBSTR types in order to work with COM. And then, every so often, a new “sheriff” would attempt to unify things under a single “standard” class, which meant the introduction of TCHAR, wchar_t *, std::string and std::wstring. (Of course, as we all know, unifying under a new standard just makes things worse.)

So that’s really eight not-quite-compatible string types.

It was definitely a learning experience (if for no other reason than the anti-patterns), but I very much enjoy the fact that the C#, Java, and JavaScript languages only have one string type apiece.

Docker Tips

I’ve been working with Docker the past few months and all-in-all, I’ve been very pleased with the quality of the documentation. But, as with any other tool, there are always a few tricks to pick up, particularly when trying to script things out for an automated build or deployment. I’ve listed some of the more useful ones below and will update this post as I learn new ones.

Note: These are mainly oriented around running Docker in a Linux environment, as that’s where I’m currently using it.

How do I stop typing sudo all the time?

Docker runs as root, so when you’re working with an out-of-the-box installation, the docker command must be preceded by sudo. Since it may not be desirable for all Docker users to be able to execute commands as root, the installation creates a docker group. Members of the group may execute docker commands without elevated privileges.

To add users to the group, execute the command:
sudo usermod -aG docker <username>

How do I remove all stopped containers?

When a container is stopped, it remains loaded. You can remove it by issuing the command docker rm container_name, but that can be a hassle if you have a large number of containers loaded and they all have random names (a frequent occurrence when you’re first learning Docker).

You can remove all stopped containers by executing the command:
docker rm $(docker ps --quiet -a --filter status=exited)

(The –filter option prevents errors from attempting to remove containers which are currently running.)

You can also cause your containers to remove themselves automatically by including the –rm option on the docker run command line.

How do I know if a container is running?

To determine if a named container (e.g. “clever_leakey”) is currently running

containerID=$(docker ps --quiet --filter status=running --filter name=clever_leakey)

if $containerID is non-null, the named container is running. If it’s null, then the container is no longer running.

Do note however that there are other non-running states, e.g. paused, which will also return a null containerID for this test. As an alternative, to find only the containers which are stopped, use status=exited.

If the docker run command includes the –rm option, the container will be removed from memory.

(Image via openclipart under Creative Commans CC0 1.0 Universal)