Bash Tips and Tricks

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.

History

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:

Using Bash History

Using Bash History

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.

Key Combinations

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:

Colored Man Pages

Colored Man Pages

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.

This entry was posted in Uncategorized. Bookmark the permalink.



9 Responses to Bash Tips and Tricks

  1. Hi, would you please fix a miscopypaste in cd - example, it now looks a bit confusing.

    As for bash tips, I really like to put in command prompt the current dir’s git repo status and rvm gemset (if any). There are snippets over the internet in plenty.

    Reply  |  Quote
  2. Guillaume FRANCE Mozilla Firefox Ubuntu Linux says:

    I don’t understand how this works:

    # don't put duplicate lines in the history
    export HISTCONTROL=ignoredups
    # ... and ignore same successive entries.
    export HISTCONTROL=ignoreboth

    Doesn’t it mean that you override the HISTCONTROL value with the 2nd statement?

    Reply  |  Quote
  3. Scott Hansen UNITED STATES Mozilla Firefox Linux says:

    Thanks for the refresher! So next time it’ll be handy bash aliases and functions, right? :)

    Scott

    Reply  |  Quote
  4. Luke Maciak UNITED STATES Mozilla Firefox Windows Terminalist says:

    @ Alexei Matyushkin:

    Which typo?

    @ Guillaume:

    Thanks, I fixed it. It should just be ignoreboth. :)

    Reply  |  Quote
  5. @ Luke Maciak:
    Ooups, sorry, there was no typo.

    Reply  |  Quote
  6. ylee UNITED STATES Mozilla Firefox Ubuntu Linux says:

    I am rather fond of :

    shopt -s dirspell # Correct dir spelling
    shopt -s cdspell # Correct spelling
    shopt -s autocd # autocd

    as well as the autojump command.

    I also use in my .inputrc file:

    # Pre-pend sudo to a command
    "\C-s":"\C-asudo \C-e"

    And btw thanks for export IGNOREEOF=1 . That is handy and I am not sure how I missed that all these years, lol.

    Reply  |  Quote
  7. Luke Maciak UNITED STATES Mozilla Firefox Windows Terminalist says:

    @ ylee:

    Thanks, autojump seems kinda cool. I will definitely check it out. :)

    Reply  |  Quote
  8. I just added colored man pages to my .zshenv; so much more legible!!

    Thanks!!

    Reply  |  Quote
  9. Poppy UNITED STATES Mozilla Firefox Windows says:

    Good topic and suggestions, all.

    I’ve become much more reliant on my directory stack. Using one letter aliases to display them and to flip between them.

    alias d='dirs -v'
    alias 1='pushd +1'
    alias 2= 'pushd +2'
    alias 3='pushd +3' (etc.)

    Recently I’ve started to save and restore the directory stack between shell session because I end up holding 5 or 6 useful locations in them. (Yes, my browser sessions have far too many tabs, too.)

    Because shell sessions can terminate abruptly and lose your history and directory I like to do

    PROMPT_COMMAND='history -a; dirs -l -p > ~/.bash_dirs_${HOST}'

    and, during startup, check for the existence of the dir stack file and push each unique non-home entry onto the dir stack.

    history -n ${HISTFILE}
    if test -r ~/.bash_dirs_${HOST}; then
    for d in `uniq ~/.bash_dirs_${HOST}` ; do
    if test $d != $HOME; then
    pushd -n "$d" > /dev/null
    fi
    done
    fi

    Reply  |  Quote

Leave a Reply

Your email address will not be published. Required fields are marked *