Programming Languages

Tutorial: Tap the Hidden Power of Your Bash Command History

6 Mar 2019 6:00am, by

Last month I wrote about combining a series of Unix commands using pipes. But there are times where you don’t even need pipes to turn a carefully-chosen series of commands into a powerful and convenient home-grown utility.

Which of course gives me a chance to tell a favorite tall tale about my first programming job — and the crazy, Rube Goldberg-style solution I eventually developed.

Think of it as an instructive letter from one newbie to another.

Rube_Goldberg's 'Self-Operating Napkin' (cropped) - Originally published in Collier's, September 26 1931 (public domain via Wikipedia)

My first year as a Perl programmer, I’d kept reminding myself of the mantra of Perl creator Larry Wall — that the three great virtues of a programmer are Laziness, Impatience and Hubris. Unfortunately, at the time I only knew a handful of Unix commands — and none did exactly what I wanted.

The echo command repeats whatever text is entered after it, for example. I’d just never found it particularly useful, since it always seemed to be more trouble than it’s worth. Sure, echo was handy for adding decorations to output.

echo "--------------------------" ; date ; echo "--------------------------"
--------------------------
Thu Feb 28 01:25:46 UTC 2019
--------------------------

But if you have to type in all those decorations in the first place, you’re not really saving any time.

What I’d really wanted (instead of echo) was a command to drop me back into that one deep-down subdirectory where I was doing most of my work. Something that was shorter than

cd ~/subdirectory/subdirectory/subdirectory/subdirectory/subdirectory

Yes, there’s a command that lets you change back to your last-used directory.

cd -

But unfortunately, I was using three directories — and always seemed to need to switch back to that one that I hadn’t used last.

So day after day, year after year — well, it’s always the small things that drive you crazy, until inevitably you start looking for alternatives. Making things even more difficult, I was sharing those directories with other developers and felt self-conscious about leaving any extra scripts lying around that might make it easier to change directories.

But eventually, I came up with a perfect newbie solution.

Somewhere along the way, I’d learned that ! is your gateway into Bash’s “history substitution” commands, swapping in whichever recently-entered command begins with the character string following the exclamation point. That obviously made it possible to execute that whole command again just by typing ! and its first letter.

And then I made that first command be the one command that I never used for anything else: echo.

echo; cd ~/directory/subdirectory/subdirectory/subdirectory/subdirectory

So I could finally change back to that directory whenever I wanted to just by typing these two characters.

!e

Programmers talk about overloading a function (or a method) — basically, creating different versions of a subroutine that would behave differently if there are extra parameters. I told myself that I’d invented something entirely new: I’d overloaded a command. Now I could finally treat bash just like vi — where a series of one- or two-character commands triggered powerful responses doing everything I needed.

And soon I was applying my new-found powers to the rest of the workflow…

For example, my supervisor had insisted that I check the syntax on any Perl code that I wrote — and of course, that command involved yet-another long series of subdirectories.

perl -I/home/davidc/perl/lib -wc filename

And since the filename was always changing, this would be harder to automate. But not impossible…

Obviously, I’d have to get that ever-changing file name. But after closing a file, I could run the history command, then use tail to extract only the last two commands — the last of which would be me typing my history command, but the one before it being the command to edit the file.

history | tail -2
496 2019-02-28 02:11:01 vi filename.pm
497 2019-02-28 02:11:59 history | tail -2

Using a slightly longer command could trim it down to just that all-important command with the filename (using head.)

history | tail -2 | head -1
496 2019-02-28 02:11:01 vi filename.pm

The filename was always in the fifth chunk of text — which of course, I could extract using awk.

history | tail -2 | head -1 | awk -F " " '{print $5}'
filename.pm

And fortunately, there’s a Unix command —  xargs — which can then magically convert that output into the argument for your next Unix command. In my case, the next command would be that gnarly syntax-checking perl instruction.

history | tail -2 | head -1 | awk -F " " '{print $5}' | xargs perl -I/home/davidc/perl/lib -wc

Voila! Now if I ever need to check the syntax of a file I’d just edited, I had a series of commands that could do it instantly. And again, I could then run that entire series of commands by just typing its very first character after !

!h
filename.pm syntax OK

Here’s what it gets truly crazy. At first, it seemed like this would only work if I never used another command that started with the letter h. But then I realized that, of course, there’s yet-another workaround. It didn’t have to be the letter h. I could make up a non-existent command — say, zarkfum — just so I could use the same trick with a less-commonly-used letter.

zarkfum; history | tail -2 | head -1 | awk -F " " '{print $5}' | xargs perl -I/home/davidc/perl/lib -wc

The whole series of commands now happened whenever I typed these two characters.

!z
-bash: zarkfum: command not found
filename.pm syntax OK

(Although eventually, I added a screen-clearing command —  just to avoid getting endless reminders that zarkfum isn’t a real command.)

zarkfum; clear ; history | tail -2 | head -1 | awk -F " " '{print $5}' | xargs perl -I/home/davidc/perl/lib -wc

Is there a cleaner, easier way to do it? Probably. But as a Perl programmer, I’d already committed to memory the Perl language’s official motto: “There’s more than one way to do it.”

And in all the years to come, out here in the real world, with its mind-numbingly repetitive workflows, I’ve found that it’s really easy to slip into using the same small handful of bash commands, over and over again. But I always learned a lot when other programmers shared their own favorite tricks. Maybe sharing my own first collection of useful commands can teach something useful to someone else.

And maybe someday they’ll combine them into their own crazy Rube Goldberg-style solutions.

After all, the possibilities really are endless, which is part of what I love about working as a programmer. And I’m not the only one who thinks so. Just this afternoon I re-read Unix’s old man page for Perl, and smiled when I saw that its last note still reminds readers that Perl’s motto is “There’s more than one way to do it.”

But it also added an extra line.

“Divining how many more is left as an exercise to the reader.”

Feature image: Strom-Masten im Osten von Mannheim (Wikipedia)

A newsletter digest of the week’s most important stories & analyses.

View / Add Comments

Please stay on topic and be respectful of others. Review our Terms of Use.