Improving bash

by Juliet Kemp

Bash is one of those Unix things that I am fully aware has a lot more potential and power than I know how to use. Every so often I go looking for another handful of useful things to learn about it: this is a selection of recent ones.

Firstly: the Debian bash package includes a file /etc/bash_completion which extends bash - for example, enabling zsh-style tab completion of hostnames. Source this file in your own .bashrc to get this functionality. It also makes it easy to extend/program bash yourself, via the directory /etc/bash_completion.d/, which is automatically sourced by /etc/bash_completion. For example, suppose you have a script foo.sh which takes hostnames as arguments (e.g. one which applies a particular command across a set of hostnames). You can get hostname tab-completion on foo.sh by creating a file /etc/bash_completion.d/foo which contains the line

complete -F _known_hosts foo.sh
You can also, of course, can get a lot more complicated - this article talks about getting tab-completion for any other arguments to foo.sh.

Secondly: $CDPATH is to cd what $PATH is to executables. Set $CDPATH in your .bashrc as follows:

export CDPATH=.:~:/usr/local/:/opt/my/long/dir/path
Then if you wish to change to /opt/my/long/dir/path/subdir, just type cd subdir at the prompt and you're there. Note that you do need to include . in there or you won't be able to change directories within your current directory.

Thirdly, some small useful .bashrc things:

  • shopt -s cdspell will attempt to correct misspellings of directories.
  • shopt -s dotglob allows files beginning with a dot to be returned in filename expansions.
  • export HISTCONTROL=ignoreboth stops the bash history from including either duplicate lines, or lines beginning with a space, which makes it rather quicker to navigate.
and some small useful command-line shortcuts:
  • Ctrl-r searches backwards in your bash history. I love this one very much.
  • Alt-. (that's a full stop there) inserts at the cursor the last argument to the previous command.
  • Alt-Ctrl-y inserts at the cursor the first argument to the previous command. Further: if you hit Alt-3 then Alt-Ctrl-y, you'll get the 3rd argument to the previous command.

Finally: a little snippet for your .bashrc that will change the title of your xterm or xterm-alike to show username@hostname:/current/directory. It updates as you change directory or ssh to another host. This is useful if you spend a lot of time opening lots of xterms on various hosts and in various directories; and it's another visual clue as to (e.g.) whether you're currently logged in as root. Myself, I also set my root prompts to be in a different colour to my own prompts. You can't have too many reminders of your identity...

case $TERM in
    xterm*)
        PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}:${PWD}\007"'
        ;;
    *)
        ;;
esac

Comments with other useful bash bits and pieces welcome!


12 Comments

Matt Doar
2007-02-01 15:18:27
Adding the CVS branch name to your prompt


If you tend to forget which branch you're working on, this incantation adds (and colors) the branch name to the prompt.


export PS1="[\u@\h\$(if [ -d CVS ]; then if [ -e CVS/Tag ]; then cat CVS/Tag | sed -e 's/^T/ /' | sed -e 's/^N/ /' | sed -e 's/^D/ Date /' | sed -e 's/_BRANCH/\[\033]12;blue\007\]/'; else echo ' \[\033]12;black\007\]MAIN' ; fi; else echo '
\[\033]12;black\007\]' ;fi) \W]\\$ "


(The line breaks are probably messed up)


I did a similar thing for subversion too, but can't find it at the moment.

Saint Aardvark
2007-02-02 09:55:09
When I started working on different machines, I'd sometimes forget which OS I was working on. This prompt helped:


UNAME=`uname`
PS1="\[\e[31;1m\]($UNAME)\[\e[37;1m\]\[[\e]2;\h:\u\a\e[0;36m\]\]\h:\[\e[m\e[0;32m\w\e[m]\]\\$ "

bash ninja
2007-02-02 16:20:53
for pros only ...


$ export HISTSIZE=10000
$ alias h="history | grep "


$ h some_command
6114 some_command with args


$ !6114
some_command with args

bhaskar
2007-02-03 19:17:32
I put up a webpage about some advanced tricks for bash, a while ago.
Check it out.
http://bhaskarvk.info/technology/bash-tricks.html


thanks

Sean
2007-02-04 20:47:15
I love CDPATH, but I can't see to get tab completion working with it. Any tips?


As far as adding to the conversation, I've always had an alias like this (whether in tcsh, bash, ksh, etc):


alias realias='source ~/.bash_profile'

Some Reader
2007-02-05 02:26:18
Javascript Prompt-o-matic


http://www.gilesorr.com/bashprompt/jsb/prompt.html


Frank Endrullat
2007-02-05 05:00:24
Recently I came accross this: http://osxdaily.com/2006/12/11/how-to-customize-your-terminal-prompt/ which includes a link in the comments to http://phil.cryer.us/code/dotfiles/bashrc which in turn resulted in my following /etc/bashrc on my PowerBook under OS X 10.4.8 (I think the rest of it originated on one of my Linux boxes...):


# System-wide .bashrc file for interactive bash(1) shells.
# set a fancy prompt (non-color, unless we know we "want" color)


# if [ -n "$PS1" ]; then PS1='\h:\w \u\$ '; fi
# Make bash check it's window size after a process completes
shopt -s checkwinsize


export PATH=$PATH:/usr/X11R6/bin:/opt/local/bin:~/bin
export TERM=xterm-color


##
# DELUXE-USR-LOCAL-BIN-INSERT
# (do not remove this comment)
##
echo $PATH | grep -q -s "/usr/local/bin"
if [ $? -eq 1 ] ; then
PATH=$PATH:/usr/local/bin
export PATH
fi



# Set a fancy prompt (non-color)
case $TERM in
xterm* | aterm | rxvt | screen )
XTITLE="\[\e]0;\u@\h \w\a\]" ;;
* )
XTITLE="" ;;
esac


# if [ -n "$PS1" ]; then PS1="$XTITLE""[\033[01;32m\][\t] [\u@\h] \[\033[01;34m\]\w \$\[\033[00m\] "; fi



# some more ls aliases
alias ll='ls -l'
alias la='ls -A'
alias l='ls -CF'


##################################################
# Fancy PWD display function
##################################################
# The home directory (HOME) is replaced with a ~
# The last pwdmaxlen characters of the PWD are displayed
# Leading partial directory names are striped off
# /home/me/stuff -> ~/stuff if USER=me
# /usr/share/big_dir_name -> ../share/big_dir_name if pwdmaxlen=20
##################################################
bash_prompt_command() {
# How many characters of the $PWD should be kept
local pwdmaxlen=25
# Indicate that there has been dir truncation
local trunc_symbol=".."
local dir=${PWD##*/}
pwdmaxlen=$(( ( pwdmaxlen < ${#dir} ) ? ${#dir} : pwdmaxlen ))
NEW_PWD=${PWD/$HOME/~}
local pwdoffset=$(( ${#NEW_PWD} - pwdmaxlen ))
if [ ${pwdoffset} -gt "0" ]
then
NEW_PWD=${NEW_PWD:$pwdoffset:$pwdmaxlen}
NEW_PWD=${trunc_symbol}/${NEW_PWD#*/}
fi
}


bash_prompt() {
if [ -n "$PS1" ]; then PS1="$XTITLE""\033[01;32m\][\t] [\u@\h] \[\033[01;34m\]\${NEW_PWD} \\$\[\033[00m\] "; fi
}


export PROMPT_COMMAND=bash_prompt_command
bash_prompt
unset bash_prompt



Juliet Kemp
2007-02-05 05:32:35
Thanks for all the comments!


Sean: sorry, it Just Worked for me, I'm afraid, so I'm not sure what to suggest. I have a version of your realias alias, as well!

jeremiah foster
2007-02-08 04:08:33
You can put functions in your .bashrc file too, I have a couple that I use a lot, like this one. It calls debian's apt-cache tool to search for a keyword I give it on the command line. Here is the code snippet I have in .bashrc;


show ()
{
apt-cache search $1
}


And here is how I use it:


$ show cgi


Yeah, this only saves a little typing, but I am lazy. :)

Sean
2007-02-16 07:07:52
Ahh, well, maybe my issue is I don't have /etc/bash_completion on my machine (OSX 10.4.8). There's a /usr/share/zsh/4.2.3/functions/_bash_completions file, but if I try to source it in bash, I get errors. I'll have to check around. Having tab completion along with CDPATH would be fantastic.
crouse
2007-03-15 12:00:48
http://bashscripts.org/viewforum.php?f=28
A few alias's dotfiles and alot of tips there. ;)
Ben
2007-08-04 19:38:44
Wow, thanks a lot for these tricks and shortcuts. very good article.