Apply Now

Prefer using email? Say hi at hello@datasciencesouth.com

Three Uncommon Bash Tricks

Type less on the terminal with these underused Bash patterns.

Good developers type less - allowing them to:

  • work faster,
  • work more accurately,
  • make less mistakes,
  • reducing stress on your their ever so tired hands.

One way to type less is to make proper use of your shell (commonly Bash). That’s what this post is about - three Bash tricks that will let you type less.

The three Bash tips covered in this post are:

  1. parameter expansion with {a,b} - to avoid retyping on a single command
  2. accessing the last argument with $_ - to avoid retyping from the last command
  3. quick substitution with ^old^new - to quickly change part of the last command

All of these tricks are compatible with zsh.

This post follows the convention of starting shell commands with a $. For commands that would be expanded by the shell, we show the expanded command below without a $.

Parameter expansion with {a,b}

When writing a single command, it’s common to repeat yourself.

Take the example of changing the suffix on a file, which we can do using mv:

1
$ mv README.txt README.md

Notice how we write README twice?

Parameter expansion will avoids this repetition - allowing us to change the suffix on our file without typing README twice:

1
2
$ mv README.{txt,md}
mv README.txt README.md

The parameter expansion we use is {txt,md}, which is expanded to two arguments - txt md (separated by a space).

Parameter expansion creates one argument for each element inside the curly braces, separated by a comma:

1
2
3
4
5
$ echo {1,2,3}
1 2 3

$  echo pre{1,2,3}fix
pre1fix pre2fix pre3fix

An empty entry will create an argument with nothing substituted:

1
2
$ echo pre{,1,2}fix
prefix pre1fix pre2fix

Another example - renaming a models folder to ml inside a data folder:

1
$ mv data/models data/ml

We can save retyping data/ by using parameter expansion:

1
2
$ mv data/{models,ml}
mv data/models data/ml

We can use parameter expansion with a sequence of numbers - useful to create numbered directories:

1
2
$ mkdir data{0..2}
mkdir data0 data1 data2

We can also do parameter expansion inside an argument - for example to change a folder halfway up a path:

1
2
$ cat models/{baseline,final}/data.csv
cat models/baseline/data.csv models/final/data.csv

A final example, using three parameters - moving two Python test files into a tests folder:

1
2
$ mv tests{_unit.py,_system.py,}
mv tests_unit.py tests_system.py tests

Any time you are retyping something multiple times in a single command, it’s likely parameter expansion can help save your exhausted hands.

Accessing the last argument with $_

Terminals are operated by a sequence of commands - we often reuse information across multiple commands.

Our previous tip, parameter expansion, is about typing less on a single command - this tip is about typing less across multiple commands.

Take the simple case of making a folder and moving into it:

1
2
$ mkdir temp
$ cd temp

Notice that we reuse the argument temp again in our second command?

We can saving retyping temp and bring it forward from the previous command using $_:

1
2
3
$ mkdir temp
$ cd $_
cd temp

Above we use $_ to access the last argument of the previous command, which in this case is temp.

This use case of wanting to reuse the last argument of the last command (here temp) is so common, that Bash stores it in a special variable _, which we access using a $ prefix (same as for $PATH or $HOME).

Another example of using $_ - moving a file and printing to STDOUT using cat:

1
2
$ mv main.py src/main.py 
$ cat src/main.py

Notice how we are again reusing the last argument src/main.py?

You can rewrite this using $_ to automatically bring forward src/main.py into your second command:

1
2
3
$ mv main.py src/main.py 
$ cat $_
cat src/main.py

Using $_ means you don’t need to rewrite a complicated file path, giving you no chance to incorrectly retype it.

Any time you are retyping something multiple times across multiple commands, it’s likely using $_ can help reduce the strain on your weary hands.

Quick substitution with ^old^new

Sometimes (often in our case) we run a command in the Shell and quickly realize we made a mistake.

Rather than retyping the command again, we can use quick substitution to fix the mistake by replacing text in the previous command.

An example - you are SSHing into a server and run the command to connect - only to realise it should be have user instead of ubuntu all along!

1
$ ssh ubuntu@198.compute.com

Instead of retyping the entire command again, you can use quick substitution to change just the part you want - here to change ubuntu into user:

1
2
$ ^ubuntu^user
ssh user@198.compute.com

The pattern in quick substitution is ^old^new. It is the equivalent of doing:

1
$ !!:s/old/new

!! to get the last command and :s for a substitute regex. I think you’ll agree ^old^new is a little easier :)

Any time you are retyping something multiple times across multiple commands, it’s likely using $_ can help reduce the strain on your weary hands.


Thanks for reading!

If you enjoyed this, check out Customizing Jupyter Lab Shortcuts for another guide on getting the most out of your tooling.