— Thomas Carlyle
— anonymous
— anonymous
Five years ago, I wrote a popular post called “Working the Bash Shell Like a Pro“, a short collection of essential tips and tricks for working efficiently with the Bash shell.
Like everyone, during my daily interaction with Bash I use many “tricks”, however, only few of them qualify for being added to my original list. Now, the time has come for a small update.
1. The Bash Curse
As you already know from the previous post, ‘!#’ selects the “entire command-line typed so far”, ‘:1’ takes the first argument in the “command-line typed so far” and ‘:r’ strips the extension from it. So changing the file extension of a file can be done with a fairly short command-line:
1 2 3 |
$ mv some/long/path/to/file.c !#:1:r.cpp |
which is — depending on the path length — a lot shorter than
1 2 3 |
$ mv some/long/path/to/file.c some/long/path/to/file.cpp |
Instead of picking the first argument by employing the ‘:1’ word designator you could equally well take the last argument by specifying ‘:$’. Why? There is only one argument typed so far (“some/long/path/to/file.c”), so the first argument is the last argument. Consequently, this achieves the same effect as the previous command:
1 2 3 |
$ mv some/long/path/to/file.c !#:$:r.cpp |
You probably think that this hasn’t gained us much since the number of characters to type hasn’t changed. That’s true but Bash has a special shortcut for ‘!#:$’ which is ‘!#$’. This saves us the colon and hence one character:
1 2 3 |
$ mv some/long/path/to/file.c !#$:r.cpp |
Since ‘!#$’ looks like a grawlix, I call this character sequence the “Bash curse”. I often use it many times a day, whenever I need to reuse (parts) of the argument preceding the argument I’m currently typing.
2. Skipping History
All of the mentioned tricks depend heavily on Bash’s history feature. After all, we want to save time by reusing something we typed earlier. Sometimes, however, we would rather not mess up our history. Take this command-line, for example:
1 2 3 |
$ conan install .. -pr:b x86_64.profile -pr:h armv8.profile |
Let’s further assume that you need to execute this regularly, many times a day. If you haven’t created an alias for it, you’ll probably pull the CTRL-R stunt*, something which I also explained in my previous post. So you hit CTRL-R and start typing “conan install”. Immediately, the desired command-line shows up and all you have to do is hit “Enter” to execute it.
So far so good. Sometimes, however, you want to fine-tune the command-line, for instance, to do a release build:
1 2 3 |
$ conan install .. -pr:b x86_64.profile -pr:h armv8.profile -s build_type=Release |
After you executed this command, your next attempt to retrieve the original command-line via CTRL-R will first find the one containing ‘-s build_type=Release’ which is not what you want as you only rarely want to do release builds. So it would have been better if the release build command-line had never been recorded in Bash’s history.
Another example of when you don’t want something to be entered in you Bash history is when you provide passwords/credentials on the command-line, as in
1 2 3 |
$ curl -u john.coder:s3cr3t http://shadysite.com |
So how do you avoid that something is remembered in Bash? It’s easy. Just put a single space before the command you are about to execute:
1 2 3 |
$ curl -u john.coder:s3cr3t http://shadysite.com |
This concludes service pack 1. Don’t expect service pack 2 anytime soon…
*) If I had to give up all the Bash tricks and only keep one, I’d would keep — hands down — the CTRL-R trick [back]