We haven’t done one of these threads in a while have we? Let’s share our favorite shell tips and tricks. I’ll talk about Bash because that’s what I use in my day-to-day work. If you happen to be Zsh user, please share your favorite tricks as well.
Here is an idea – save all the histories! We are running modern computers with lots of memory and storage space: we might as well preserve our bash history forever (or at the very least for a very long time). This gives us an opportunity to do reverse search, and thus avoid typing same commands over and over. It also helps with forensics, in case you need to find out what went wrong with your system.
Here is what I usually put in my .bashrc:
# save all the histories export HISTFILESIZE=1000000 export HISTSIZE=1000000
Since we’re allowing our command history to accumulate, it is a good idea to try to keep it as tidy as possible. This involves removing duplicate commands, and combining multi-line commands so that they can be re-run from the history with ease:
# don't put duplicate lines or empty spaces in the history export HISTCONTROL=ignoreboth # combine multiline commands in history shopt -s cmdhist
Sometimes you have multiple terminal windows open at the same time. By default, the window that closes last, will overwrite the bash history file, loosing the history of all the other terminal windows and ssh sessions in the process. This can be avoided by this little setting:
# merge session histories shopt -s histappend
Most users are aware that you can use the ↑ and ↓ keys to browse/repeat the recent commands. That’s merely the tip of the iceberg.
Using the History Effectively
As you know, you can see your command history at any time by issuing the history command. The entries in the history are marked sequentially and the exclamation mark can be used to run these commands by number like this:
There are better ways of using the exclamation mark though. For example, my favorite history expansion command is !! which repeats the last command. How is this different from ↑+Enter? Well, consider the following example:
# re-run last command with sudo sudo !!
I use this shortcut every time I need to install something on Ubuntu. Or edit something in /etc. No, I’m not joking – I always forget sudo and ever since I learned this little trick, I think I saved hundreds of key-strokes per month.
My second favorite expansion is !?. It works just like the above, but you can use it to re-run the last command that matches the string that immediately follows it. For example:
# re-run last apt-get command with sudo sudo !?apt
It is useful for those occasions when you forget sudo, then mistype something, or go do something else, and then you want to re-run the command few lines later.
Third favorite history expansion is !$ which expands into the last argument of last command. This one expands to the last argument of the last command. It’s probably best to use an example here:
# trying to copy file to directory you don't own cp foo.dat /some/long/path/that/is/annoying/to/type/ # let's take ownership of that dir sudo chown luke !$
That last trick can actually be accomplished with a single key stroke: Alt+.. If you happen to be working on a Mac, you can use Esc, . (Esc, then dot) instead.
There is also a $^ expansion, which as you can probably guess returns the first argument of the last command.
If you just typed in a really long, complicated command and managed to mess it up, you can use fc (fix command) to load said command in your default editor. You can then fix it, taking full benefit of syntax highlighting and editor features. Once you save and quit, the command will be executed automatically.
If you want to jump straight into editor driven command composition, you can simply hit Ctrl+X, Ctrl+E. This will open a blank editor window, and then execute the buffer contents upon exiting.
Finally, if you only remember one keystroke from this post, it should be Ctrl+R which is the reverse incremental search through history. Simply hit it, and start typing a command and options from your history should pop up immediately. You can execute them by hitting Enter or continue hitting Ctrl+R to go further down the history lane.
Pretty much everyone knows that Ctrl+C kills the current process and that Ctrl+D will quit current shell and log you out. I like to put this in my .bashrc to prevent that last thing happening by accident:
# Ctrl+D must be pressed twice export IGNOREEOF=1
Most people do know that Ctrl+Z will suspend and background a running task, and that it can be brought back to focus using the fg (foreground) command (or that a list of suspended tasks can be seen by running jobs). But there are a lot more key-strokes that most people are unaware of.
Bash actually uses a lot of Emacs key bindings. You could set it to Vim mode, but that might get little weird at times. I prefer to keep it in the default Emacs mode to keep things simple. Here are a few important keyboard shortcuts to remember:
- Ctrl+A – jump to the beginning of the line
- Ctrl+E – jump to the end of the line
- Ctrl+U – clear the line
- Ctrl+L – clear the screen
- Ctrl+W – delete last word
- Ctrl+K – delete to the end of the line
- Alt+T – swap current word with previous (also Esc, T)
- Alt+F – jump one word forward (also Esc, F)
- Alt+B – jump one word backward (also Esc, B)
- Alt+U – uppercase till the end of line (also Esc, U)
- Alt+u – lowercase till the end of line (also Esc, u)
- Alt+. – insert last arbument (also Esc, .)
- Ctrl+R – reverse incremental history search
- Ctrl+X, Ctrl+E – open default text editor to edit a command
There are more, but these are the ones I use most often.
Colorize Your World
By default bash is pretty boring color wise. This is of course by design, since in the past there was always a chance you could be logging in from a teletype or a dumb terminal that could not handle color codes. These days this is not much of a concern so I like to spruce up my shell a bit like this:
# enable colors eval "`dircolors -b`" # force ls to always use color and type indicators alias ls='ls -hF --color=auto' # make the dir command work kinda like in windows (long format) alias dir='ls --color=auto --format=long' # make grep highlight results using color export GREP_OPTIONS='--color=auto'
I also like to colorize my man pages (and all less output in general):
# colorful man pages export LESS_TERMCAP_mb=$'\E[01;31m' export LESS_TERMCAP_md=$'\E[01;31m' export LESS_TERMCAP_me=$'\E[0m' export LESS_TERMCAP_se=$'\E[0m' # end the info box export LESS_TERMCAP_so=$'\E[01;42;30m' # begin the info box export LESS_TERMCAP_ue=$'\E[0m' export LESS_TERMCAP_us=$'\E[01;32m'
The end result looks pretty good:
When possible, I like to use alternate commands that are more visually pleasing. For example colordiff instead of plain old diff, and htop instead of top. Unfortunately these are not always installed on new systems. I usually handle this situation like this:
# use colordiff instead of diff if available command -v colordiff >/dev/null 2>&1 && alias diff="colordiff -u" # use htop instead of top if installed command -v htop >/dev/null 2>&1 && alias top=htop
The command -v bit checks if the app in question is installed, and creates the alias only if it is found. I’m redirecting the output so that I don’t get error messages scrolling on the screen when I log in.
And some other stuff…
Here is a few remaining bits that didn’t fit into the previous categories:
# corrects typos (eg: cd /ect becomes cd /etc) shopt -s cdspell # resize ouput to fit window shopt -s checkwinsize
I often see people using cd ~ command which is quite redundant. Typing in cd on its own, without arguments takes you to your home directory anyway. While visually similar, the cd – command is much, much more useful. It takes you to the last directory that you were in. It is great for jumping between two different directories without the need to use pushd and popd:
cd /some/long/path cd /some/other/path cd - # takes you to /some/long/path cd - # takes you to /some/other/path
Finally, there is the < operator. It is sort of the reverse of > in that it forces bash to treat the output of the command as a temporary file (but you don’t have to specify the name). Perhaps an example is in order:
# treat output as file diff /etc/hosts <(ssh somewherelese cat /etc/hosts)
That's about all that I have for now. What are your favorite tips and tricks for your shell of choice (be it bash, zsh, tcsh or something else entirely). Let me know in the comments.