My Favorite Bash Shenanigans
We've all been there: typing a long command, hitting enter, and then realizing you need to re-run it with just one small change. Or maybe you're constantly jumping between directories, wishing there was a quicker way. If so, you're in the right place. In this blog you'll discover how to work smarter, not harder, in Bash.
Bash History: The Time Machine of Your Terminal
The history command is a handy one. History allows me to see what commands I ran on a particular system or arguments were passed to that command. I use history to re-run commands without having to remember anything.
The record of recent commands is stored by default in ~/.bash_history.This location can be changed by modifying the HISTFILE shell variable.
There are other variables, such as:
HISTSIZE(lines to store in memory for the current session)HISTFILESIZE(how many lines to keep in the history file)
Lets says I run apt update command and I get permission denied error.
abdrehman:~$ apt update
Reading package lists... Done
E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied)
E: Unable to lock directory /var/lib/apt/lists/
W: Problem unlinking the file /var/cache/apt/pkgcache.bin - RemoveCaches (13: Permission denied)
W: Problem unlinking the file /var/cache/apt/srcpkgcache.bin - RemoveCaches (13: Permission denied)
I can use !! to repeat the last command from history.
abdrehman:~$ sudo !!
sudo apt update
[sudo] password for abdrehman:
Hit:1 https://download.docker.com/linux/ubuntu noble InRelease
Get:2 https://apt.releases.hashicorp.com noble InRelease [12.9 kB]
Fetched 4,326 kB in 3s (1,252 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
100 packages can be upgraded. Run 'apt list --upgradable' to see them.
What if I want to display the last four commands in my history? I enter: history 4
abdrehman@:~$ history 4
1998 tail /dev/random
1999 tail -f /dev/random
2000 clear
2001 history 4
Now if I want to re run a command like this:
abdrehman@:~$ !1999
tail -f /dev/random
Reusing the Last Argument
When I want to list directory contents for different directories, I may change between directories quite often. There is a nice trick you can use to refer to the last argument of the previous command. For example:
$> ls some/very/long/path/to/some/directory
foo-file bar-file baz-file
In the above example, /some/very/long/path/to/some/directory is the last argument of the previous command.
If I want to cd (change directory) to that location, I can use $_ something like this:
$> cd $_
$> pwd
/home/username/some/very/long/path/to/some/directory
Aliases: Your Personal Bash Shortcuts
Aliases in Bash allow you to create shortcuts for long or frequently used commands. This makes it easier to execute complex commands with a simple keyword.
To create an alias, use the syntax alias name='command', where name is the shortcut you want to use, and command is the full command you want to run.
Here are few of my aliases:
alias k='kubectl'
alias gs='git status'
alias ssh-keygen="ssh-keygen -t ed25519"
alias fileman="nautilus --browser"
To make an alias permanent, add it to your ~/.bashrc or ~/.bash_profile file.
Redirection and Streams
Piping and redirection helps me create powerful workflows that can automate my work, saving time and effort.
Every program we run on the command line automatically has three data streams connected to it.
- STDIN (0): Standard input (data fed into the program)
- STDOUT (1): Standard output (data printed by the program, defaults to the terminal)
- STDERR (2): Standard error (for error messages, also defaults to the terminal)
Redirecting to a File ( > )
Normally, we will get our output on the screen, which is convenient most of the time, but sometimes we may wish to save it into a file to keep as a record, feed into another system, or send to someone else. The greater than operator > ndicates to the command line that we wish the programs output (or whatever it sends to STDOUT) to be saved in a file instead of printed to the screen. Let's see an example.
abdrehman@:~$ ls
barry.txt bob example.png firstfile foo1 video.mpeg
abdrehman@:~$ ls > myoutput
abdrehman@:~$ ls
barry.txt bob example.png firstfile foo1 myoutput video.mpeg
abdrehman@:~$ cat myoutput
barry.txt
bob
example.png
firstfile
foo1
myoutput
video.mpegIf we redirect to a file which does not exist, it will be created automatically for us. If we save into a file which already exists, however, then it's contents will be cleared, then the new output saved to it.
We can instead get the new data to be appended to the file by using the double greater than operator >>.
Redirecting from a File ( < )
If we use the less than operator < then we can send data the other way. We will read data from the file and feed it into the program via it's STDIN stream.
abdrehman@:~$ wc -l < barry.txt
7We may easily combine the two forms of redirection we have seen so far into a single. See next example.
abdrehman@: wc -l < barry.txt > myoutput
abdrehman@: cat myoutput
7Piping
So far we've dealt with sending data to and from files. Now we'll take a look at a mechanism for sending data from one program to another. It's called piping and the operator we use is |. What this operator does is feed the output from the program on the left as input to the program on the right.
abdrehman@:~$ ls
barry.txt bob example.png firstfile foo1 myoutput video.mpeg
abdrehman@:~$ ls | head -3
barry.txt
bob
example.png
abdrehman@: ls | head -3 | tail -1
example.png