summaryrefslogtreecommitdiff
path: root/saved-articles/sensible bash · small & opinionated selection of basic bash configurations for an improved command-line user experience.txt
blob: e970206e4fadc0b613a6656b668e404274ca33b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
---
title: Sensible Bash · Small & opinionated selection of basic Bash configurations for an improved command-line user experience
date: 2016-03-03T14:45:30Z
source: http://mrzool.cc/writing/sensible-bash/
tags: linux, programming, bash

---

####  Written on December 10, 2015 by [mrzool][1]

[ Tweet ][2]

###  Small & opinionated selection of basic Bash configurations for an improved command-line user experience

there's a small set of simple Bash options that removes certain limitations typical of command-line interfaces and can dramatically improve the user experience. These options enable small optimizations that might not seem like a big deal at first, but every keystroke saved adds up rapidly if you're a heavy terminal user. After reading this article, you will be able to use Bash to move into directories using less keystrokes, enjoy a smarter tab completion, work with a command history that actually makes sense, and jump everywhere in your file system at the speed of thought. All this without relying on any convoluted hack, just plain native or quasi-native Bash options.

Every option listed in this article is [packaged in a repo on GitHub][3] and can be enabled from your Bash configuration file, namely `bashrc` or `bash_profile`. The difference between the two is clearly explained in [this short post][4] by Josh Staiger. If you're on OS X, I recommend you to follow Josh's advice of sourcing `bashrc` from `bash_profile` so to keep all your configuration in one place. I will assume you did this throughout the rest of the article.

A couple of caveats before jumping in: since changes to Bash configuration require you to reload your config file to become effective, you might want to save you some typing by setting up an alias that does that:

    alias refresh='source ~/.bashrc'

Also, make sure you have the [Bash Completion][5] package installed and properly configured on your system, as some of the options described here will not work properly without it.

### Smarter tab completion

[Readline][6] is the GNU library that provides an unified interface for advanced line editing to CLI programs like Bash. As command-line user, you use it all the time. Tab completion? Powered by Readline. Emacs-like key bindings like `C-w` to delete back one word? Powered by Readline. Incremental history search? Powered by Readline.

The capabilities provided by Readline are so symbiotic to Bash that most users consider them native Bash features (this is what I meant above with _quasi-native_ Bash options). They're not, but we can set them from our `bashrc` anyway using the built-in Bash command `bind`. Here are my favorites, each improving a different aspect of tab completion:

    bind "set completion-ignore-case on"
    bind "set completion-map-case on"
    bind "set show-all-if-ambiguous on"

The option **`completion-ignore-case`** tells Readline to perform filename completion in a case-insensitive fashion. This is almost always what you want, and it comes in handy particularly on OS X, where system folders are capitalized by default: I no longer need to press `<Shift>` when I want to `cd` into `Documents`, typing `cd do<Tab>` will be enough.

With **`completion-map-case`**, filename matching during completion will treat hyphens and underscores as equivalent. Since in most keyboard layouts typing an underscore usually requires pressing `<Shift>`, that's another keystroke saved. This option requires `completion-ignore-case` to be enabled.

Lastly, **`show-all-of-ambiguous`** will get Readline to display all possible matches for an ambiguous pattern at the first `<Tab>` press instead of at the second. This is another small UX improvement you will get used to in no time.

There are tons of other cool Readline runtime behaviors you can activate, like [vi-like key bindings][7] or some clever [history-search tweaks][8]. As your configuration grows, consider using a dedicated `initrc`, Readline's [default configuration file][9], instead of cluttering your `bashrc` with too many `bind` statements. This is [mine][10].

### Better History

Most of the options below are taken from the article [Better Bash History][11] by Tom Ryder. They enable history behaviors that make sense and ease the job when it comes to searching or parsing the archive. Each line is briefly explained by a comment, refer to the [original post][11] if you want to dig deeper.

    # Append to the history file, don't overwrite it
    shopt -s histappend

    # Save multi-line commands as one command
    shopt -s cmdhist

    # Record each line as it gets issued
    PROMPT_COMMAND='history -a'

    # Huge history. Doesn't appear to slow things down, so why not?
    HISTSIZE=500000
    HISTFILESIZE=100000

    # Avoid duplicate entries
    HISTCONTROL="erasedups:ignoreboth"

    # Don't record some commands
    export HISTIGNORE="&:[ ]*:exit:ls:bg:fg:history"

    # Useful timestamp format
    HISTTIMEFORMAT='%F %T '

### Better, faster directory navigation I

Here are three lovely options that will considerably speed up the way you navigate through the file system:

    shopt -s autocd
    shopt -s dirspell
    shopt -s cdspell

The option **`autocd`** will spare you the hassle of typing `cd` every time you need to navigate into a directory. You just need to type the name of your target: Bash will understand what you want and prepend `cd` for you. This also works for the common shortcut `..` to go to the parent directory. Sadly, it doesn't work for `-` to go back to the previous working directory, but you can get around that by setting up an alias using this [clever trick][12].

In addition, **`dirspell`** and **`cdspell`** will get Bash to autocorrect minor spelling errors like transposed characters in directory names: the former during tab completion, the latter in arguments already supplied to the `cd` command.

### Better, faster directory navigation II

By default, `cd` will look in the current directory for possible targets you might want to move into. This behavior is defined by the environment variable **`CDPATH`**, that thus looks like `CDPATH="."` by default. You can add more paths to this variable by separating them with a colon. This is how my `CDPATH` looks:

Simply enough, I've added the directory where I keep all my projects (`~/repos`) to the list of possible `cd` targets. Now, whenever I want to jump to a particular project, I just have to type its name's first letters at my prompt. As soon as I press `<Tab>`, the project's name I'm looking for will pop up in the suggestions and I'll be able to jump into it right away, regardless of my current directory. No more typing long and complex paths at the prompt.

My `~/repos` folder is the only place I want to be able to rapidly jump into wherever I am, so this slightly conservative `CDPATH` definition is enough for my needs. Feel free to add more folders—just try to limit yourself to those that are actually important to avoid requiring a pager every time you tab-complete a `cd` command.

Let's now look at another native option, `cdable_vars`, that has a similar effect but allows for finer-grained control.

### Better, faster directory navigation III

In case you were using this [nifty hack][13] to bookmark your favorite directories to be able to jump into them from everywhere—like I did until not so long ago—I have good news for you: You can stop using it right away. This ability is already baked into Bash and can be enabled through the native option `cdable_vars`:

With this option set, we can then define and export variables containing paths to our most important directories and `cd` into them from our prompt, thus enabling a simple, effective and hack-free bookmarking system:

    # Don't use ~ to define your home here, it won't work.
    export dotfiles="$HOME/dotfiles"
    export repos="$HOME/repos"
    export documents="$HOME/Documents"
    export dropbox="$HOME/Dropbox"

Now `cd documents` will take you right into `~/Documents` from wherever you are when you issue the command. If you have [Bash Completion][5] installed and configured, tab completion will also expand your `cdable_vars`, besides the target folders you've set in `CDPATH`.

## Conclusion

As said at the beginning, I came to rely on this setup so much that it has become my new default, so I packaged it in a [repo on GitHub][3] that's meant to be something along the lines of Tim Pope's [sensible.vim][14]. If you think I've missed something important, you can open an issue, send a pull request or let me know on [Twitter][15].

—[Mattia Tezzele][16]

Thanks for reading so far! For comments, suggestions, questions and corrections you can always reach me on [Twitter][15]. You can also subscribe to the [RSS feed][17] to be notified of new posts.

[1]: / "Homepage"
[2]: https://twitter.com/intent/tweet?text=Sensible Bash&url=http://localhost:3000/writing/sensible-bash/&via=mrzool_&related=mrzool_ "Share on Twitter"
[3]: https://github.com/mrzool/bash-sensible
[4]: http://www.joshstaiger.org/archives/2005/07/bash_profile_vs.html
[5]: http://bash-completion.alioth.debian.org/
[6]: https://cnswww.cns.cwru.edu/php/chet/readline/rltop.html
[7]: http://blog.sanctum.geek.nz/vi-mode-in-bash/
[8]: https://coderwall.com/p/oqtj8w/the-single-most-useful-thing-in-bash
[9]: http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC9
[10]: https://github.com/mrzool/dotfiles/blob/master/inputrc
[11]: http://blog.sanctum.geek.nz/better-bash-history/
[12]: http://askubuntu.com/questions/146031/bash-alias-alias-name-should-be-a-simple-dash-not-working
[13]: http://jeroenjanssens.com/2013/08/16/quickly-navigate-your-filesystem-from-the-command-line.html
[14]: https://github.com/tpope/vim-sensible
[15]: http://twitter.com/mrzool_
[16]: http://mrzool.cc
[17]: /feed.xml