Skip to main content
  1. Posts/

Ding! Your Dotfiles

·9 mins
linux dotfiles

The initial publication was on 6-1-2022 and republished on 12-29-2022.

“Ding!” Leveling Up Your Dotfiles>

“Ding!” Leveling Up Your Dotfiles #

I want to introduce the concept of dotfiles and why they are essential to customizing a shell environment. The goal is to make working in a Command Line Interface (CLI) more comfortable and identify workflows that work best for you.

Dotfiles start with a . and are generally stored in the user’s home directory. Files that begin with a dot are marked as hidden (still readable) and thus make great spots to store configuration data.

sh, bash, and zsh>

sh, bash, and zsh #

For most *Nix operating systems, you will have either sh, bash, or zsh as the default shell. Bash is “Bourne Again SHell” and is an improvement of the original Bourne shell (sh). Zsh is an extended version of the Bourne shell and is similar to Bash but offers more complex features.

This guide will have examples for both Bash and Zsh. I personally use Zsh but have dotfiles prepared for both shells.

To change the default shell:

sudo chsh -s $(which zsh)
sudo chsh -s $(which bash)
Why is the shell important?>

Why is the shell important? #

The CLI will be the primary workspace for interacting with many tools, and being familiar with how to use its features to your advantage can save a lot of time. Quickly navigating command history, using a multiplexer, navigating a text editor, using command aliases, format output, and utilizing configuration files will help you focus on results rather than process.

Customizing the Shell>

Customizing the Shell #

The primary configuration files are .zshrc and .bashrc. These files manipulate the shell’s functionality and appearance as it loads. They can also be refreshed with the source ~/.zshrc command.

History Control>

History Control #

Configuration options are available to control the command history stored within the .bash_history and .zsh_history files. These files can expand the history limit to store more commands and improve the quality by not storing duplicated commands.

Command history is important because there are several plugins like fzf that use command history to fill out autocomplete suggestions and recursive history searching to find those epic one liners again.

.bashrc:

# History control

HISTCONTROL=ignoredups:ignorespace
HISTSIZE=100000
HISTFILESIZE=2000000
shopt -s histappend
shopt -s cdspell
bind TAB:menu-complete

.zshrc:

# History control

HISTFILE=~/.zsh_history
HISTCONTROL=ignoredups:ignorespace
HISTSIZE=50000000
HISTFILESIZE=50000000
SAVEHIST=50000000
setopt INC_APPEND_HISTORY
setopt HIST_IGNORE_ALL_DUPS
setopt HIST_SAVE_NO_DUPS
setopt HIST_FIND_NO_DUPS
Aliases>

Aliases #

Aliases are an excellent way to save commands with consistent functionality. Think of them as the in-between option for saving complex commands between a one-liner and a fully flushed-out bash script. They are also helpful to hardcode certain functionality for commands like ls.

.bashrc & .zshrc:

# Alias definitions
alias ls='ls --color=auto -lashx'
alias ll='ls --color=auto -lash'
alias la='ls --color=auto -A'
alias l='ls --color=auto -CF'
alias ks='ls -lashtx'
alias ld='ls -lashtx'
alias :q="exit"
alias :qa="exit"
alias :wq="exit"
alias _='sudo'
alias ipa='ip -br a'
alias curl='grc curl'

# alias file
if [ -f ~/.sh_aliases ]; then
    . ~/.sh_aliases
fi

You can place aliases directly into the .bashrc and .zshrc files or create a separate command file that you can import into your shell.

For example, the following is a commonly used function stored within my .sh_aliases file that includes help text when not enough arguments are provided:

# unqiue sort file

usort() {
	if [[ $# -ne 1 ]]; then
		echo 'unique sort file inplace'
		echo 'EXAMPLE: usort <FILE>'
	else
		LC_ALL=C sort -u $1 -T ./ -o $1
	fi
}
Environmental Variables>

Environmental Variables #

Dotfiles can be used to load environmental variables that can help customize the shell further and store frequently used information such as directory paths or parameters.

.bashrc & .zshrc:

# Color
export TERM="xterm-256color"

# Vim
export EDITOR=/usr/bin/vim

# PATH
export PATH=~/.local/bin:/snap/bin:/usr/sandbox/:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:$PATH$

# Go
export GOROOT=/usr/lib/go
export GOPATH=$HOME/go
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH

# Ports
export PORTS_HTTP_XL='80,81,300,443,591,593,832,981,1010,1311,2082,2087,2095,2096,2480,3000,3128,3333,4243,4567,4711,4712,4993,5000,5104,5108,5800,6543,7000,7396,7474,8000,8001,8008,8014,8042,8069,8080,8081,8088,8090,8091,8118,8123,8172,8222,8243,8280,8281,8333,8443,8500,8834,8880,8888,8983,9000,9043,9060,9080,9090,9091,9200,9443,9800,9981,12443,16080,18091,18092,20720,28017'
export PORTS_HTTP='80,443,8080,8443'

The export command will create two environmental variables that hold commonly used ports, so instead of typing everything out, I can access them by using $PORTS_HTTP_XL in commands.

Syntax Highlighting and Plugins>

Syntax Highlighting and Plugins #

Plugins offer a powerful way to extend the basic shell functionality and provide advanced customization options. One advantage zsh has over bash is the amount of plugin support.

The following are some of my favorites:

  • fzf → command-line fuzzy finder, which can extend shell history searching
  • zsh-z → allows you to quickly jump to past directories with partial matching
  • zsh-syntax-highlighting → syntax highlighting in the CLI to see errors as you type

I use only a few plugins, for others are intrusive or change too many options. The three above are minimal and offer powerful functionality and customization options.

.zshrc:

# Syntax highlighting, Z, and fzf
source /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
source ~/.zsh/zsh-z.plugin.zsh
autoload -U compinit && compinit
source /usr/share/doc/fzf/examples/key-bindings.zsh
source /usr/share/doc/fzf/examples/completion.zsh
Suggestions>

Suggestions #

The zsh shell also supports a suggestion feature that can help autocomplete make better guesses with case-insensitive completion, partial completion, and other options to improve navigation and tab completion.

.zshrc:

# Suggestions
zstyle ':autocomplete:tab:*' insert-unambiguous yes
zstyle ':completion:*' menu select
zstyle ':autocomplete:*' min-input 2

# case insensitive path-completion
zstyle ':completion:*' matcher-list 'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]} l:|=* r:|=*' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]} l:|=* r:|=*' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]} l:|=* r:|=*'

# partial completion suggestions
zstyle ':completion:*' list-suffixes
zstyle ':completion:*' expand prefix suffix
Searching History>

Searching History #

The zsh command history can also perform substring searching, making history searching more dynamic. The following will only show completions starting with what was already typed and other minor changes.

.zshrc:

# Fix searching
autoload -U up-line-or-beginning-search
autoload -U down-line-or-beginning-search
zle -N up-line-or-beginning-search
zle -N down-line-or-beginning-search
bindkey "$key[Up]" up-line-or-beginning-search
bindkey "$key[Down]" down-line-or-beginning-search

Also see .inputrc in “Other Configuration Dotfiles” for bash users.

Prompt>

Prompt #

The shell prompt itself can also be visually customized. This is good for reducing visual clutter or supporting different color schemes for users affected by colorblindness or other visual limitations. You can also add items to appear in the prompt such as the hostname or command output.

.bashrc:

# Colors
txtblk='\[\e[0;30m\]' # Black
txtred='\[\e[0;31m\]' # Red
txtgrn='\[\e[0;32m\]' # Green
txtylw='\[\e[0;33m\]' # Yellow
txtblu='\[\e[0;34m\]' # Blue
txtpur='\[\e[0;35m\]' # Purple
txtcyn='\[\e[0;36m\]' # Cyan
txtwht='\[\e[0;37m\]' # White
txtrst='\[\e[0m\]'    # Text Reset

# Prompt colours
atC="${txtgrn}"
nameC="${txtwht}"
hostC="${txtwht}"
pathC="${txtblu}"
gitC="${txtcyn}"
pointerC="${txtgrn}"
normalC="${txtrst}"
borderC="${txtgrn}"

# Prompt
PROMPT_COMMAND=__prompt_command
__prompt_command() {
    local EXIT="$?"
    PS1=''

    if [ $EXIT -eq 127 ]; then
        pointerC="${txtpur}"
        atC="${txtpur}"
        borderC="${txtpur}"
    elif [ $EXIT -eq 1 ]; then
        pointerC="${txtred}"
        atC="${txtred}"
        borderC="${txtred}"
    else 
        pointerC="${txtgrn}"
        atC="${txtgrn}"
        borderC="${txtgrn}"
    fi
    PS1+="${nameC}\u${atC}@${hostC}\h${atC}:${borderC}[${pathC}\w${borderC}]${pointerC}\n$ ${normalC}"
}

.zshrc:

# Prompt colours
nameC="%F{#ffffff}"
hostC="%F{#ffffff}"
pathC="%F{172}"
gitC="%F{245}"
pointerC="%F{34}"

# Prompt
NEWLINE=$'\n'
PROMPT="%f${nameC}%n%(?.${pointerC}.%F{9})@%f${hostC}%m%f%(?.${pointerC}.%F{9}):%f%(?.${pointerC}.%F{9})[%f${pathC}%~%f%(?.${pointerC}.%F{9})]%f%(?.${pointerC}.%F{9})${NEWLINE}$ %f"

The above prompts will respond to conditional logic, such as the previous command’s output code. The syntax is slightly different between zsh and bash.

Misc.>

Misc. #

.bashrc:

# mute terminal
bind 'set bell-style none'

.zshrc:

# Arrow binds
bindkey '^[[1;5C' forward-word                    # ctrl + ->
bindkey '^[[1;5D' backward-word                   # ctrl + <-
bindkey '^[[1;3C' forward-word                    # alt + ->
bindkey '^[[1;3D' backward-word                   # alt + <-

# mute terminal
unsetopt BEEP
Other Configuration Dotfiles>

Other Configuration Dotfiles #

.inputrc>

.inputrc #

The .inputrc file can also affect searching history for bash users but will apply to all GNU Readline library programs.

# "prefix history" search
set show-all-if-ambiguous on
set completion-ignore-case on 
.curlrc>

.curlrc #

The .curlrc modifies the curl command. This can be helpful when integrating curl into your workflows, as you can set options to be included with every request.

# Set silent mode
silent

# Dump headers to stdout
--dump-header -

# Set user agent
-A "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13"

# When needed for TLS (same as -k)
insecure

# Send to proxy
#proxy = 127.0.0.1:8080

# Change the below referrer URL or comment it out entirely
#-e "https://www.google.com"

# Method and Data
#-x POST
#-d "TEST"

# Headers
#-H  "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
#-H  "Upgrade-Insecure-Requests: 1"
#-H  "Accept-Encoding: gzip, deflate, sdch"
#-H  "Accept-Language: en-US,en;q=0.8"

# Verbose
#--verbose

# Follow redirects
#--location
Grc>

Grc #

Grc is a frontend for the generic colorizer grcat. It can produce colorized output for commands that may not support color options. It can be useful for those who prefer color when reading large amounts of output.

The following will create a file with aliases that can be loaded into your .zshrc or .bashrc file to colorize all possible commands.

#!/bin/bash

for cmd in g++ gas head make ld ping6 tail traceroute6 $( ls /usr/share/grc/ ); do
  cmd="${cmd##*conf.}"
  type "${cmd}" >/dev/null 2>&1 && echo "alias '${cmd}"="$( which grc) --colour=auto ${cmd}'" >> ~/.grc_aliases
done

You can manually create a file for tools such as curl and highlight keywords. For example, the following is a snip from my conf.curl file, which I place into /usr/share/grc/conf.curl:

# curl grc colorizer configuration
===
# Interesting HTTP Headers (x-headers)
regexp=^X-.*|^x-.*
colours=magenta
===
# Interesting HTTP Headers (CORs)
regexp=^Access-Control-.*|^access-control-.*
colours=yellow
===
# Interesting HTTP Headers (content)
regexp=^Content-Security-.*|^Content-Length:.*|^Content-Type:.*|^Server:.*|^content-security-.*|^content-length:.*|^content-type:.*|^server:.*|^set-cookie:.*
colours=cyan
===
# URLS
regexp=(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])
colours=red
===
Tmux>

Tmux #

Tmux is a terminal multiplexer that runs as a daemon in the background. A significant advantage of using a multiplexer is that sessions are saved and stored, so the workspace will persist even if the terminal window is closed.

A popular configuration for tmux is oh-my-tmux, which supports several advanced features. The primary files used are .tmux.conf and .tmux.conf.local; each controls specific settings such as the prefix key and display.

Tmux has a lot of functionality to unpack, so we will not mention it here, but my configuration is linked at the end of the article.

Vim>

Vim #

For those who prefer to use Vim, an entire community of people creates plugins and content for you. I use vim-plug to manage plugins and keep a minimalistic setup.

" Only a preview of the full file

" Dont try to be vi compatible
set nocompatible

" Helps force plugins to load correctly when it is turned back on below
filetype off

" Load plugins
call plug#begin()
Plug 'bling/vim-airline'
Plug 'vim-airline/vim-airline-themes'
Plug 'jacoborus/tender.vim'
Plug 'fatih/vim-go', { 'do': ':GoUpdateBinaries' }

" Initialize plugin system
call plug#end()

" Turn on syntax highlighting
syntax on

" For plugins to load correctly
filetype plugin indent on
Deployment and Management>

Deployment and Management #

Stow>

Stow #

After creating your dotfiles, you can use stow to quickly set them up in a new environment. It will create a symlink between the file and where it should appear on the file system for centralized storage.

Docker>

Docker #

Another desirable option is setting up your configuration in Docker and using a Dockerfile to assist in managing the installation. Once the setup is complete, you can spawn infinite environments and tear them down when you are done.

I use both of the above tools in my full configuration which can be found here.

Final Thoughts>

Final Thoughts #

There are many ways to customize the shell to assist in your workflows. Often open-source tools will also have their own configuration files, which you can add to your dotfiles and customize their configuration.

Ultimately, these options are available to you as tools; what matters more is what you do with them, hopefully faster now. Thank you for reading, and my complete configuration can be found here.