Showing posts with label profile. Show all posts
Showing posts with label profile. Show all posts

Sunday, August 31, 2014

My Git Aliases

A git alias gives you the ability to run a long or hard-to-remember git command using a simple name. They are configured in your .gitconfig file.

One of my favourite aliases is git ls which lists all your commits in a nice format. In addition, git ll shows you what files were committed in each commit.

My git aliases are shown below. (For the latest version of my .gitconfig, visit my GitHub dotfiles repository):

[alias]
    st = status
    co = checkout
    br = branch
    df = diff
    ci = commit
    ca = commit -a --amend -C HEAD
    desc = describe
    rb = rebase -i master --autosquash
    cp = cherry-pick

    who = shortlog -s --
    ls = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)[%an]%Creset' --abbrev-commit --date=relative
    ll = log --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)[%an]%Creset' --decorate --numstat
    ld = log --pretty=format:'%C(red)%h %Cgreen%ad%C(yellow)%d %Creset%s%C(bold blue) [%cn]%Creset' --decorate --date=short

    # list aliases
    la = "!git config -l | grep alias | cut -c 7-"

If you have any useful aliases, please share them in the comments section below.

You might also like:
My Bash Profile
My Bash Aliases

Saturday, June 30, 2012

vim: Change statusline colour based on mode

Here is my vimrc statusline configuration:
" statusline
" format markers:
"   %t File name (tail) of file in the buffer
"   %m Modified flag, text is " [+]"; " [-]" if 'modifiable' is off.
"   %r Readonly flag, text is " [RO]".
"   %y Type of file in the buffer, e.g., " [vim]".
"   %= Separation point between left and right aligned items.
"   %l Line number.
"   %L Number of lines in buffer.
"   %c Column number.
"   %P percentage through buffer
set statusline=%t\ %m%r%y%=(ascii=\%03.3b,hex=\%02.2B)\ (%l/%L,%c)\ (%P)
set laststatus=2
" change highlighting based on mode
if version >= 700
  highlight statusLine cterm=bold ctermfg=black ctermbg=red
  au InsertLeave * highlight StatusLine cterm=bold ctermfg=black ctermbg=red
  au InsertEnter * highlight StatusLine cterm=bold ctermfg=black ctermbg=green
endif
It displays some useful information about the file and your position within it. It also automatically changes the colour of the statusline from red to green when you enter INSERT mode and back to red when you leave it.

This is what the status line looks like in INSERT mode:

Foo.java [RO][java] (ascii=097,hex=61) (158/667,23) (26%)

To see a description of all possible status line variables type :help statusline in vim.

To see my complete vimrc visit my GitHub dotfiles repository.

Sunday, October 02, 2011

Better Bash Completion for Tmux

In my previous post, I wrote about how awesome tmux is for managing multiple terminals. However, even though it is widely used, I haven't been able to find a good Bash completion script for it. The tmux package does come with bash_completion_tmux.sh but this does not complete command options or command aliases. So I wrote a better version which completes tmux commands, aliases and their options. However, there is still room for improvement. It would be nice if it could complete session and window names too, but I haven't found the time to implement this yet.

Here is a demo:

$ tmux lis[TAB]
list-buffers   list-clients   list-commands
list-keys      list-panes     list-sessions  list-windows

$ tmux list-windows -[TAB]
-a -t

$ tmux list-windows -a
sharfah:0: less [180x82] [layout f0de,180x82,0,0]
sharfah:1: tmp [180x82] [layout f0de,180x82,0,0] (active)
sharfah:2: isengard [180x82] [layout f0de,180x82,0,0]
sharfah:3: java [180x82] [layout f0de,180x82,0,0]
My completion script is shown below. You need to source it in your Bash profile. Alternatively, save it to your Bash completion directory e.g. ~/.bash/.bash/.bash_completion.d and it should automatically get picked up.

The script is also available in my GitHub dotfiles repository. If you can improve it, fork it and send me a pull request!

#
# tmux completion
# by Fahd Shariff
#
_tmux() {
  # an array of commands and their options
  declare -A tmux_cmd_map
  tmux_cmd_map=( ["attach-session"]="-dr -t target-session" \
                 ["bind-key"]="-cnr -t key-table key command arguments" \
                 ["break-pane"]="-d -t target-pane" \
                 ["capture-pane"]="-b buffer-index -E end-line -S start-line -t target-pane" \
                 ["choose-buffer"]="-t target-window template" \
                 ["choose-client"]="-t target-window template" \
                 ["choose-session"]="-t target-window template" \
                 ["choose-window"]="-t target-window template" \
                 ["clear-history"]="-t target-pane" \
                 ["clock-mode"]="-t target-pane" \
                 ["command-prompt"]="-I inputs -p prompts -t target-client template" \
                 ["confirm-before"]="-p prompt -t target-client command" \
                 ["copy-mode"]="-u -t target-pane" \
                 ["delete-buffer"]="-b buffer-index" \
                 ["detach-client"]="-P -s target-session -t target-client" \
                 ["display-message"]="-p -c target-client -t target-pane message" \
                 ["display-panes"]="-t target-client" \
                 ["find-window"]="-t target-window match-string" \
                 ["has-session"]="-t target-session" \
                 ["if-shell"]="shell-command command" \
                 ["join-pane"]="-dhv -p percentage|-l size -s src-pane -t dst-pane" \
                 ["kill-pane"]="-a -t target-pane" \
                 ["kill-server"]="kill-server" \
                 ["kill-session"]="-t target-session" \
                 ["kill-window"]="-t target-window" \
                 ["last-pane"]="-t target-window" \
                 ["last-window"]="-t target-session" \
                 ["link-window"]="-dk -s src-window -t dst-window" \
                 ["list-buffers"]="list-buffers" \
                 ["list-clients"]="-t target-session" \
                 ["list-commands"]="list-commands" \
                 ["list-keys"]="-t key-table" \
                 ["list-panes"]="-as -t target" \
                 ["list-sessions"]="list-sessions" \
                 ["list-windows"]="-a -t target-session" \
                 ["load-buffer"]="-b buffer-index path" \
                 ["lock-client"]="-t target-client" \
                 ["lock-server"]="lock-server" \
                 ["lock-session"]="-t target-session" \
                 ["move-window"]="-dk -s src-window -t dst-window" \
                 ["new-session"]="-d -n window-name -s session-name -t target-session -x width -y height command" \
                 ["new-window"]="-adk -n window-name -t target-window command" \
                 ["next-layout"]="-t target-window" \
                 ["next-window"]="-a -t target-session" \
                 ["paste-buffer"]="-dr -s separator -b buffer-index -t target-pane" \
                 ["pipe-pane"]="-t target-pane-o command" \
                 ["previous-layout"]="-t target-window" \
                 ["previous-window"]="-a -t target-session" \
                 ["refresh-client"]="-t target-client" \
                 ["rename-session"]="-t target-session new-name" \
                 ["rename-window"]="-t target-window new-name" \
                 ["resize-pane"]="-DLRU -t target-pane adjustment" \
                 ["respawn-pane"]="-k -t target-pane command" \
                 ["respawn-window"]="-k -t target-window command" \
                 ["rotate-window"]="-DU -t target-window" \
                 ["run-shell"]="command" \
                 ["save-buffer"]="-a -b buffer-index" \
                 ["select-layout"]="-np -t target-window layout-name" \
                 ["select-pane"]="-lDLRU -t target-pane" \
                 ["select-window"]="-lnp -t target-window" \
                 ["send-keys"]="-t target-pane key " \
                 ["send-prefix"]="-t target-pane" \
                 ["server-info"]="server-info" \
                 ["set-buffer"]="-b buffer-index data" \
                 ["set-environment"]="-gru -t target-session name value" \
                 ["set-option"]="-agsuw -t target-session|target-window option value" \
                 ["set-window-option"]="-agu -t target-window option value" \
                 ["show-buffer"]="-b buffer-index" \
                 ["show-environment"]="-g -t target-session" \
                 ["show-messages"]="-t target-client" \
                 ["show-options"]="-gsw -t target-session|target-window" \
                 ["show-window-options"]="-g -t target-window" \
                 ["source-file"]="path" \
                 ["split-window"]="-dhvP -p percentage|-l size -t target-pane command" \
                 ["start-server"]="start-server" \
                 ["suspend-client"]="-t target-client" \
                 ["swap-pane"]="-dDU -s src-pane -t dst-pane" \
                 ["swap-window"]="-d -s src-window -t dst-window" \
                 ["switch-client"]="-lnp -c target-client -t target-session" \
                 ["unbind-key"]="-acn -t key-table key" \
                 ["unlink-window"]="-k -t target-window" )

   declare -A tmux_alias_map
   tmux_alias_map=( ["attach"]="attach-session" \
                  ["detach"]="detach-client" \
                  ["has"]="has-session" \
                  ["lsc"]="list-clients" \
                  ["lscm"]="list-commands" \
                  ["ls"]="list-sessions" \
                  ["lockc"]="lock-client" \
                  ["locks"]="lock-session" \
                  ["new"]="new-session" \
                  ["refresh"]="refresh-client" \
                  ["rename"]="rename-session" \
                  ["showmsgs"]="show-messages" \
                  ["source"]="source-file" \
                  ["start"]="start-server" \
                  ["suspendc"]="suspend-client" \
                  ["switchc"]="switch-client" \
                  ["breakp"]="break-pane" \
                  ["capturep"]="target-pane]" \
                  ["displayp"]="display-panes" \
                  ["findw"]="find-window" \
                  ["joinp"]="join-pane" \
                  ["killp"]="kill-pane" \
                  ["killw"]="kill-window" \
                  ["lastp"]="last-pane" \
                  ["last"]="last-window" \
                  ["linkw"]="link-window" \
                  ["lsp"]="list-panes" \
                  ["lsw"]="list-windows" \
                  ["movew"]="move-window" \
                  ["neww"]="new-window" \
                  ["nextl"]="next-layout" \
                  ["next"]="next-window" \
                  ["pipep"]="pipe-pane" \
                  ["prevl"]="previous-layout" \
                  ["prev"]="previous-window" \
                  ["renamew"]="rename-window" \
                  ["resizep"]="resize-pane" \
                  ["respawnp"]="respawn-pane" \
                  ["respawnw"]="respawn-window" \
                  ["rotatew"]="rotate-window" \
                  ["selectl"]="select-layout" \
                  ["selectp"]="select-pane" \
                  ["selectw"]="select-window" \
                  ["splitw"]="[shell-command]" \
                  ["swapp"]="swap-pane" \
                  ["swapw"]="swap-window" \
                  ["unlinkw"]="unlink-window" \
                  ["bind"]="bind-key" \
                  ["lsk"]="list-keys" \
                  ["send"]="send-keys" \
                  ["unbind"]="unbind-key" \
                  ["set"]="set-option" \
                  ["setw"]="set-window-option" \
                  ["show"]="show-options" \
                  ["showw"]="show-window-options" \
                  ["setenv"]="set-environment" \
                  ["showenv"]="show-environment" \
                  ["confirm"]="confirm-before" \
                  ["display"]="display-message" \
                  ["clearhist"]="clear-history" \
                  ["deleteb"]="delete-buffer" \
                  ["lsb"]="list-buffers" \
                  ["loadb"]="load-buffer" \
                  ["pasteb"]="paste-buffer" \
                  ["saveb"]="save-buffer" \
                  ["setb"]="set-buffer" \
                  ["showb"]="show-buffer" \
                  ["if"]="if-shell" \
                  ["lock"]="lock-server" \
                  ["run"]="run-shell" \
                  ["info"]="server-info" )

   local cur="${COMP_WORDS[COMP_CWORD]}"
   local prev="${COMP_WORDS[COMP_CWORD-1]}"
   COMPREPLY=()

   # completing an option
   if [[ "$cur" == -* ]]; then
     #tmux options
     if [[ "$prev" == "tmux" ]]; then
         COMPREPLY=( $( compgen -W "-2 -8 -c -f -L -l -q -S -u -v -V" -- $cur ) )
     else
         #find the tmux command so that we can complete the options
         local cmd="$prev"
         local i=$COMP_CWORD
         while [[ "$cmd" == -* ]]
         do
             cmd="${COMP_WORDS[i]}"
             ((i--))
         done

         #if it is an alias, look up what the alias maps to
         local alias_cmd=${tmux_alias_map[$cmd]}
         if [[ -n ${alias_cmd} ]]
         then
             cmd=${alias_cmd}
         fi

         #now work out the options to this command
         local opts=""
         for opt in ${tmux_cmd_map[$cmd]}
         do
              if [[ "$opt" == -* ]]; then
                  len=${#opt}
                  i=1
                  while [ $i -lt $len ]; do
                      opts="$opts -${opt:$i:1}"
                      ((i++))
                  done
              fi
         done
         COMPREPLY=($(compgen -W "$opts" -- ${cur}))
     fi
   else
     COMPREPLY=($(compgen -W "$(echo ${!tmux_cmd_map[@]} ${!tmux_alias_map[@]})" -- ${cur}))
   fi
   return 0
}
complete -F _tmux tmux
Related posts:
Managing Multiple Terminals with Tmux Writing your own Bash Completion Function

Saturday, October 01, 2011

Managing Multiple Terminals with Tmux

I've started using tmux, which is a "terminal multiplexer", similar to screen. It allows you to manage a number of terminals from a single screen. So, for example, instead of having 5 PuTTY windows cluttering up your desktop, you now have only one window, containing 5 terminals. If you close this window, you can simply open a new one and "attach" to your running tmux session, to get all your terminals back at the same state you left them in.

There are lots of cool things you can do with tmux. For example, you can split a terminal window horizontally or vertically into "panes". This allows you to look at files side by side, or simply watch a process in one pane while you do something else in another.

I took the following screenshot of tmux in action:


The status bar along the bottom shows that I have 5 terminal windows open. I am currently in the one labelled "1-demo" and within this window I have 4 panes, each running a different command.

There are quite a few key bindings to learn, but once you have mastered them you will be able to jump back and forth between windows, move them around and kill them without lifting your hands off the keyboard. You can also set your own key bindings for things you do frequently. For example, my Ctrl-b / binding splits my window vertically and opens up a specified man page on the right. My Ctrl+b S binding allows me to SSH to a server in a new window.

Here is my tmux configuration taken from ~/.tmux.conf which shows my key bindings and colour setup. You can download this file from my GitHub dotfiles repository.

bind | split-window -h
bind - split-window -v
bind _ split-window -v
bind R source-file ~/.tmux.conf \; display-message "tmux.conf reloaded!"

bind / command-prompt -p "man" "split-window -h 'man %%'"
bind S command-prompt -p "ssh" "new-window -n %1 'exec ssh %1'"
bind h split-window -h  "man tmux"

set -g terminal-overrides 'xterm*:smcup@:rmcup@'

set -g history-limit 9999

# Terminal emulator window title
set -g set-titles on
set -g set-titles-string '#S:#I.#P #W'

# notifications
setw -g monitor-activity on
setw -g visual-activity on

# auto rename
setw -g automatic-rename on

# Clock
setw -g clock-mode-colour green
setw -g clock-mode-style 24

# Window status colors
setw -g window-status-bg colour235
setw -g window-status-fg colour248
setw -g window-status-alert-attr underscore
setw -g window-status-alert-bg colour235
setw -g window-status-alert-fg colour248
setw -g window-status-current-attr bright
setw -g window-status-current-bg colour235
setw -g window-status-current-fg colour248

# Message/command input colors
set -g message-bg colour240
set -g message-fg yellow
set -g message-attr bright

# Status Bar
set -g status-bg colour235
set -g status-fg colour248
set -g status-interval 1
set -g status-left '[#H]'
set -g status-right ''

set -g pane-border-fg white
set -g pane-border-bg default
set -g pane-active-border-fg white
set -g pane-active-border-bg default

Sunday, September 25, 2011

Speeding up Bash Profile Load Time

I started noticing a considerable delay whenever opening a new terminal or connecting to another server. After profiling my Bash profile with a few time commands, I discovered that the slowest part was the loading of the completion file:
$ time  ~/.bash/.bash_completion

real    0m0.457s
user    0m0.183s
sys     0m0.276s
The Bash completion script I use is from http://bash-completion.alioth.debian.org. I found that there is an existing bug for this issue #467231: bash_completion is big and loads slowly; load-by-need proposed and someone has submitted a script to speed up Bash completion load time called dyncomp.sh.

This is a one-time script, which only needs to be run when you install your Bash completions or modify them. It loads your completions and moves the completion functions out of the script and into a separate directory. They are only loaded when needed. This speeds up the load time considerably and new terminal windows open up instantly!

$ time  ~/.bash/.bash_dyncompletion

real    0m0.020s
user    0m0.018s
sys     0m0.002s
You can visit my GitHub dotfiles repository for the latest version of my Bash profile.

Saturday, August 13, 2011

Dotfiles in Git

I've added all my dotfiles (including my entire bash profile and vimrc) to my GitHub dotfiles repository. Whenever I make any changes, I will commit them to the repository.

In order to download the latest version, go to my Downloads page. Alternatively, if you have git installed, use the following command, to clone my repository:

git clone git://github.com/sharfah/dotfiles.git
This will download them to a directory called dotfiles. You can then copy the files recursively (cp -r) to your home directory (don't forget to backup your original files first!). Alternatively, use symlinks.

Saturday, August 06, 2011

My Bash Profile - Part VI: Inputrc

inputrc is the name of the readline startup file. You can set key bindings and certain variables in this file. One of my favourite key bindings is Alt+L to ls -ltrF. I also have bindings which allow you to go back and forth across words using the Ctrl+Left/Right Arrow keys.

To take a look at all your current key bindings execute the command bind -P or bind -p. Check out the man pages for more information.

Update: My dotfiles are now in Git. For the latest version, please visit my GitHub dotfiles repository.

Here is my INPUTRC:

set bell-style none
set completion-ignore-case On
set echo-control-characters Off
set enable-keypad On
set mark-symlinked-directories On
set show-all-if-ambiguous On
set show-all-if-unmodified On
set skip-completed-text On
set visible-stats On

"\M-l": "ls -ltrF\r"
"\M-h": "dirs -v\r"

# If you type any text and press Up/Down,
# you can search your history for commands starting
# with that text
"\e[B": history-search-forward
"\e[A": history-search-backward

# Use Ctrl or Alt Arrow keys to move along words
"\C-[OD" backward-word
"\C-[OC" forward-word
"\e\e[C": forward-word
"\e\e[D": backward-word

"\M-r": forward-search-history
If you have any useful bindings, please share them in the comments section below.

More posts on my Bash profile:

Saturday, June 18, 2011

Efficiently Navigating Directories on UNIX

I find myself, like most developers, spending a lot of time navigating directories. Flipping back and forth between logs and application directories with long names can be quite tedious. So, with the help of a few new functions, aliases and config tweaks I've made the navigation process easier and more efficient. You no longer need to remember long paths because you can jump straight to them using their names. You can also choose to bookmark your favourite directories. Here is my setup:

1. Go up to a specific directory
I have a function called upto which allows you to jump up to any directory, on the current path, just by name. This is very useful if you are deep in a directory. I also have autocompletion for this function, so that it shows me valid directory names and completes them for me.

#
# Go up to the specified directory
#
upto(){
  if [ -z $1 ]; then
      echo "Usage: upto [directory]"
      return 1
  fi
  local upto=$1
  cd "${PWD/\/$upto\/*//$upto}"
}

#
# Completion function for upto
#
_upto(){
  local cur=${COMP_WORDS[COMP_CWORD]}
  d=${PWD//\//\ }
  COMPREPLY=( $( compgen -W "$d" -- $cur ) )
}
complete -F _upto upto
Example:
[/www/public_html/animals/hippopotamus/habitat/swamps/images] $ upto h[TAB][TAB]
habitat       hippopotamus
[/www/public_html/animals/hippopotamus/habitat/swamps/images] $ upto hippopotamus
[/www/public_html/animals/hippopotamus] $
2. Go up a specific number of directories
If you know how many levels you want to go up, you can use the up function e.g. up 5 will move you up 5 directories.
#
# Go up a specified number of directories
#
up(){
  if [ -z $1 ]
  then
    cd ..
    return
  fi
  local levels=$1
  local result="."
  while [ $levels -gt 0 ]
  do
    result=$result/..
    ((levels--))
  done
  cd $result
}
3. Go down to a specific directory
Sometimes you want to change to a directory but can't remember the path, or the path name is too long to type. I have a function called jd which allows you to jump down to a directory any level below the current one. It uses Bash's globstar feature so make sure you have it enabled (using shopt -s globstar). (Warning: this may be slow on large directory structures because of the searching involved.)
#
# Jumps to a directory at any level below.
# using globstar
#
jd(){
  if [ -z $1 ]; then
      echo "Usage: jd [directory]";
      return 1
  else
      cd **/$1
  fi
}
Example:
[/www/public_html/animals/hippopotamus/habitat/swamps/images] $ upto hippopotamus
[/www/public_html/animals/hippopotamus] $ jd images
[/www/public_html/animals/hippopotamus/habitat/swamps/images] $
4. CDPATH
The CDPATH variable is a colon-separated list of directories in which the shell looks for destination directories specified by the cd command. Mine is shown below. No matter what directory I am currently in, I can quickly jump to a project in my dev directory with cd <project> because it is on my path.
export CDPATH=".::..:../..:~:~/dev/"
5. Shell Options
I have set the following useful shell options in my .bashrc. The autocd option allows you to change to a directory without using the cd command and cdspell automatically corrects typos in directory names.
shopt -s cdspell     # correct dir spelling errors on cd
shopt -s autocd      # if a command is a dir name, cd to it
shopt -s cdable_vars # if cd arg is not a dir, assume it is a var
6. Quick Aliases
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'
alias .....='cd ../../../..'
alias ......='cd ../../../../..'
7. Keeping a history of visited directories
I came across a useful post on Linux Gazette: History of visited directories in BASH. It contains a script which maintains a history of directories you have visited and then allows you to switch to them easily using a reference number. The command cd -- shows you your history and cd -2 would take you to the second item in your history list. For example:
[/www/public_html/animals] $ cd --
 1  /tmp
 2  /www/public_html/animals/hippopotamus/habitat/swamps/images
 3  /www/public_html/animals/lion
[/www/public_html/animals] $ cd -2
[/www/public_html/animals/hippopotamus/habitat/swamps/images] $
8. Bookmarks
I spend a lot of time moving between different directories especially between logs and application directories. I have implemented a bookmarking feature which allows you to bookmark your favourite directories and then change to them easily.
  • bm: bookmark the current directory
  • bcd: change to the specified bookmark
  • brm: remove a bookmark
  • bcl: clear all bookmarks
  • bll: list all bookmarks
#-------------------------------
# Directory Bookmark Functions
#-------------------------------

#
# Add a bookmark, if it doesn't exist
#
bm(){
  local val=$(pwd)
  for i in ${bookmarks[@]}
  do
    if [ "$i" == "$val" ]
    then
       return 1
    fi
  done
  num=${#bookmarks[@]}
  bookmarks[$num]=$val
}

#
# Goto specified bookmark
# or previous one by default
#
bcd(){
  index=$1
  if [ -z $index ]
  then
     index=$((${#bookmarks[@]}-1))
  fi
  local val=${bookmarks[$index]}
  if [ -z $val ]
  then
     echo "No such bookmark. Type bll to list bookmarks."
     return 1
  else
     cd "$val"
  fi
}

#
# Remove a bookmark
#
brm(){
  if [ $# -lt 1 ]
  then
     echo "Usage: brm [bookmark-index]"
     return 1
  fi
  if [ -z ${bookmarks[$1]} ]
  then
     echo "No such bookmark"
     return 1
  fi
  bookmarks=(${bookmarks[@]:0:$1} ${bookmarks[@]:$(($1 + 1))})
}

#
# Remove all bookmarks
#
bcl(){
    bookmarks=()
}

#
# List all bookmarks
#
bll(){
  if [ ${#bookmarks[@]} -ne 0 ]
  then
     local i=0
     while [ $i -lt ${#bookmarks[@]} ]
     do
       echo $i: ${bookmarks[$i]}
       ((i++))
     done
  fi
  return 0
}

If you have any useful directory-related functions, share them in the comments below!

Related Posts:

Saturday, April 16, 2011

Writing your own Bash Completion Function

Bash programmable completion is a powerful feature which allows you to specify how arguments to commands should be completed. You do this using the complete command. For example, you can set completion up so that when you type the unzip command and hit the TAB key, it only shows completions for files ending with the .zip extension. Similarly, the completion for the ssh command would display hosts taken from your known_hosts file.

In this post, I will describe how you can write a custom completion function for a command foo. Bash will execute this function when foo [TAB][TAB] is typed at the prompt and will display possible completions.

Bash uses the following variables for completion:

  • COMPREPLY: an array containing possible completions as a result of your function
  • COMP_WORDS: an array containing individual command arguments typed so far
  • COMP_CWORD: the index of the command argument containing the current cursor position
  • COMP_LINE: the current command line
Therefore, if you want the current argument that you are trying to complete, you would index into the words array using: ${COMP_WORDS[COMP_CWORD]}.

So, how do you build the result array COMPREPLY? The easiest way is to use the compgen command. You can supply a list of words to compgen and a partial word, and it will show you all words that match it. Let's try it out:

sharfah@starship:~> compgen -W "mars twix twirl" tw
twix
twirl

Now we have everything we need to write our completion function:

_foo()
{
    local cur=${COMP_WORDS[COMP_CWORD]}
    COMPREPLY=( $(compgen -W "alpha beta bar baz" -- $cur) )
}
complete -F _foo foo
Save this. Mine is in ~/.bash_completion.d/foo

Demo

sharfah@starship:~> . ~/.bash_completion.d/foo
sharfah@starship:~> foo ba[TAB][TAB]
bar
baz

A Bigger Example
Here is a meatier example of Bash completion. It shows how to complete Autosys commands such as sendevent and autorep. It completes command options, events which can be sent to jobs and job names which are obtained from a file. In some cases, the completions depend on the previous argument e.g. if the previous argument is -J then we know that we have to complete job names.

# a file containing job names
export AUTOSYS_JOBFILE=~/.autosysjobs

# complete autosys jobs using the job file
_autosysjobs()
{
  local cur=${COMP_WORDS[COMP_CWORD]}
  [ ! -z ${AUTOSERV} ] && \
    COMPREPLY=( $( compgen -W "$(cat ${AUTOSYS_JOBFILE}_${AUTOSERV})" -- $cur ) )
  return 0
}

# complete sendevent
_sendevent()
{
  local cur=${COMP_WORDS[COMP_CWORD]}
  local prev=${COMP_WORDS[COMP_CWORD-1]}

  case "$prev" in
   -S)
     COMPREPLY=( $( compgen -W "$(cat $AUTOSYS_HOSTFILE)" -- $cur ) )
     return 0
     ;;
   -E)
     COMPREPLY=( $( compgen -W "STARTJOB KILLJOB DELETEJOB \
                    FORCE_STARTJOB JOB_ON_ICE JOB_OFF_ICE \
                    JOB_ON_HOLD JOB_OFF_HOLD CHANGE_STATUS \
                    STOP_DEMON CHANGE_PRIORITY COMMENT \
                    ALARM SET_GLOBAL SEND_SIGNAL" -- $cur ) )
     return 0
     ;;
   -s)
     COMPREPLY=( $( compgen -W "RUNNING STARTING SUCCESS \
                    FAILURE INACTIVE TERMINATED" -- $cur ) )
     return 0
     ;;
   -J)
     _autosysjobs
     ;;
  esac

  # completing an option
  if [[ "$cur" == -* ]]; then
          COMPREPLY=( $( compgen -W "-E -S -A -J -s -P \
                       -M -q -G -C -U -T -K" -- $cur ) )
  fi
}
complete -F _sendevent sendevent

# complete autorep
_autorep()
{
  local cur=${COMP_WORDS[COMP_CWORD]}
  local prev=${COMP_WORDS[COMP_CWORD-1]}

  case "$prev" in
   -J)
      _autosysjobs
     ;;
  esac

  # completing an option
  if [[ "$cur" == -* ]]; then
          COMPREPLY=( $( compgen -W "-J -d -s -q -o \
                    -w -r -L -z -G -M -D" -- $cur ) )
  fi
}
complete -F _autorep autorep
Related Posts:
My Bash Profile - Part III: Completions

Saturday, April 02, 2011

My vimrc

.vimrc is file used to configure Vim.

Update: My dotfiles are now in Git. For the latest version, please visit my GitHub dotfiles repository.

Here is a dump of mine:

set nocompatible        " vim, not vi
set history=50          " keep 50 lines of command line history
set ruler               " show the cursor position all the time
set noerrorbells        " don't make noise
set cursorline          " highlight current line
set laststatus=2        " always show the status line
set expandtab           " no real tabs please!
set number              " Display line numbers on the left
set showcmd             " Show partial commands in the last line of the screen
set ignorecase          " Use case insensitive search, except when using capital letters
set smartcase           " case insensitive patterns - when only lowercase is used
set smarttab            " smart tabulation and backspace
set autoindent
set showmode            " Show the current mode
set showmatch           " show matching braces
set hlsearch            " highlight searches
set incsearch           " find as you type
set title               " show title
set pastetoggle=<F11>   " F11 toggles indenting when pasting
set wildmenu            " make command-line completion bash like + menu
set wildmode=longest:full
set showcmd             " show the cmd being typed
set shiftwidth=4        " No 8 character tabs
set softtabstop=4
set undolevels=1000     " 1000 undos

" Allow backspacing over autoindent, line breaks and start of insert action
set backspace=indent,eol,start

"F10 toggles line numbers
map <silent> <F10> :set invnumber<cr>

syntax on
For a complete list of vim options check out the Vim documentation.

Friday, April 01, 2011

Add Colour to Ant Output

You can add pretty colours to your ant output really easily by simply setting the following in your profile:
export ANT_ARGS='-logger org.apache.tools.ant.listener.AnsiColorLogger'
The AnsiColorLogger adds color to the standard Ant output by prefixing and suffixing ANSI color code escape sequences to it.

Read more about it here: Apache Ant | AnsiColorLogger

Saturday, March 26, 2011

My Bash Profile - Part V: Prompt

This is what my prompt looks like:
Your Bash prompt is stored in the PS1 variable. In my prompt, I display the following items, colour coded where appropriate:
  • time (\t)
  • user (\u) - red if a production user, green otherwise
  • host (\H) - red if a production machine, green otherwise
  • working directory (_get_path) - trimmed to 80 characters
  • number of jobs currently running in the shell (\j)
  • history number of this command (\!)
  • exit status of the previous command (_get_exit_status) - green if success, red otherwise
I also have a useful function called title which allows me change my xterm's titlebar so that I can differentiate it from other xterm's.

Update: My dotfiles are now in Git. For the latest version, please visit my GitHub dotfiles repository.

Here is my prompt taken from ~/.bash_prompt.


# define some colours
GREY=$'\033[1;30m'
RED=$'\033[1;31m'
GREEN=$'\033[1;32m'
YELLOW=$'\033[1;33m'
BLUE=$'\033[1;34m'
MAGENTA=$'\033[1;35m'
CYAN=$'\033[1;36m'
WHITE=$'\033[1;37m'
NONE=$'\033[m'

# trims long paths down to 80 chars
_get_path(){
  local x=$(pwd | sed -e "s:$HOME:~:")
  local len=${#x}
  local max=80
  if [ $len -gt $max ]
  then
      echo ...${x:((len-max+3))}
  else
      echo ${x}
  fi
}

# prints a colour coded exit status
_get_exit_status(){
   local es=$?
   if [ $es -eq 0 ]
   then
       echo -e "${GREEN}${es}"
   else
       echo -e "${RED}${es}"
   fi
}

# change xterm title
title() {
   if [ $# -eq 0 ]
   then
      title=""
   else
      title="$* - "
   fi
}

# colour the host red if it is production
# all prod hostnames end with "prod"
if [[ $HOSTNAME =~ prod$ ]]
then
    HOST_COLOR=$RED
else
    HOST_COLOR=$GREEN
fi

# colour the user red if it is production
# all prod usernames end with "prod"
if [[ $USER =~ prod$ ]]
then
    USER_COLOR=$RED
else
    USER_COLOR=$GREEN
fi

#executed just before prompt
PROMPT_COMMAND='exitStatus=$(_get_exit_status);mydir=$(_get_path);'

PS1='\033]0;${title}\u@\h:`tty`>${mydir}\007\n\
\[${GREY}\][\[${BLUE}\]\t\[${GREY}\]]\
\[${GREY}\][\[${USER_COLOR}\]\u\[${GREY}\]@\[${HOST_COLOR}\]\H\[${GREY}\]] \
\[${WHITE}\]${mydir} \
\[${GREY}\](\
\[${YELLOW}\]+${SHLVL}\[${GREY}\]|\
\[${YELLOW}\]%\j\[${GREY}\]|\
\[${YELLOW}\]!\!\[${GREY}\]|\
\[${YELLOW}\]${exitStatus}\[${GREY}\])\[${NONE}\]\n\
\[${USER_COLOR}\]$\[${NONE}\] '

# continuation prompt
PS2='\[${USER_COLOR}\]>\[${NONE}\] '

#used by set -x for tracing
PS4='\[${USER_COLOR}\]+\[${NONE}\] '
References:

More posts on my Bash profile:

Saturday, March 19, 2011

My Bash Profile - Part IV: Functions

Bash functions store a series of commands for later execution. If you find yourself running a sequence of commands frequently, it would make sense to wrap them up in a function. Functions are a lot like aliases but you can also pass arguments to them.

Update: My dotfiles are now in Git. For the latest version, please visit my GitHub dotfiles repository.

Here is a list of my bash functions taken from ~/.bash_functions.

#
# Go up a specified number of directories
#
up(){
    if [ -z $1 ]
    then
      cd ..
      return
    fi
    local levels=$1
    local result="."
    while [ $levels -gt 0 ]
    do
        result=$result/..
        ((levels--))
    done
    cd $result
}

#
# Make a directory and change to it
#
mkcd(){
  if [ $# -ne 1 ]; then
         echo "Usage: mkcd <dir>"
         return 1
  else
         mkdir -p $1 && cd $1
  fi
}

#
# fast find, using globstar
#
ff(){
   ls -ltr **/$@
}

#
# Jumps to a directory at any level below.
# using globstar
#
jd(){
    if [ -z $1 ]; then
        echo "Usage: jd [directory]";
        return 1
    else
        cd **/$@
    fi
}

#
# moves file to ~/.Trash
# (use instead of rm)
#
trash(){
   if [ $# -eq 0 ]
   then
       echo Usage: trash FILE...
       return 1
   fi
   local DATE=$(date +%Y%m%d)
   [ -d "${HOME}/.Trash/${DATE}" ] || mkdir -p ${HOME}/.Trash/${DATE}
   for FILE in "$@"
   do
     mv "${FILE}" "${HOME}/.Trash/${DATE}"
     echo "${FILE} trashed!"
   done
}

#
# Calculate an expression e.g. calc 1+1
#
calc(){
    echo "$@"|bc -l;
}

#
# Calendar which starts on Monday
# Highlights current day
#
cal(){
    if [ $# -eq 0 ]
    then
        /usr/bin/cal -m  | sed "s/\($(date +%e)\)/${RED}\1${NONE}/"
    else
        /usr/bin/cal -m "$@"
    fi
}

#
# Email me a short note
#
emailme(){
    if [ $# -eq 0 ]
    then
        echo Usage: emailme text
        return 1
    fi
    echo "$*" | mailx -s "$*" fahds
    echo "Sent email"
}

#
# Prints out a long line. Useful for setting a visual flag in your terminal.
#
flag(){
    echo -e  "\e[1;36m[==============="$@"===\
              ($(date +"%A %e %B %Y %H:%M"))\
              ===============]\e[m"
}

#
# Swap two files
#
swap(){
    if [ $# -ne 2 ]
    then
        echo Usage: swap file1 file2
        return 1
    fi
    local TMPFILE=tmp.$$
    mv "$1" $TMPFILE
    mv "$2" "$1"
    mv $TMPFILE "$2"
}

#
# Backup file(s)
#
dbackup(){
    if [ $# -lt 1 ]
    then
        echo Please supply a file to backup
        return 1
    fi
    date=`date +%Y%m%d-%H%M`
    for i in "$@"
    do
        echo Backed up $i to $i.$date
        cp $i $i.$date
    done
}

#
# Extract an archive of any type
#
extract(){
   if [ $# -lt 1 ]
   then
       echo Usage: extract file
       return 1
   fi
   if [ -f $1 ] ; then
       case $1 in
           *.tar.bz2)   tar xvjf $1    ;;
           *.tar.gz)    tar xvzf $1    ;;
           *.bz2)       bunzip2 $1     ;;
           *.rar)       unrar x $1     ;;
           *.gz)        gunzip $1      ;;
           *.tar)       tar xvf $1     ;;
           *.tbz2)      tar xvjf $1    ;;
           *.tgz)       tar xvzf $1    ;;
           *.zip)       unzip $1       ;;
           *.war|*.jar) unzip $1       ;;
           *.Z)         uncompress $1  ;;
           *.7z)        7z x $1        ;;
           *)           echo "don't know how to extract '$1'..." ;;
       esac
   else
       echo "'$1' is not a valid file!"
   fi
}

#
# Creates an archive
#
roll(){
  if [ "$#" -ne 0 ] ; then
    FILE="$1"
    case "$FILE" in
      *.tar.bz2|*.tbz2) shift && tar cvjf "$FILE" $* ;;
      *.tar.gz|*.tgz)   shift && tar cvzf "$FILE" $* ;;
      *.tar)            shift && tar cvf "$FILE" $* ;;
      *.zip)            shift && zip "$FILE" $* ;;
      *.rar)            shift && rar "$FILE" $* ;;
      *.7z)             shift && 7zr a "$FILE" $* ;;
      *)                echo "'$1' cannot be rolled via roll()" ;;
    esac
  else
    echo "usage: roll [file] [contents]"
  fi
}

#
# XPath
#
xpath(){
    if [ $# -ne 2 ]
    then
       echo Usage: xpath xpath file
       return 1
    fi
    echo "cat $1" | xmllint --shell $2 | sed '/^\/ >/d'
}

#-------------------------------
# Directory Bookmark Functions
#-------------------------------

#
# Add a bookmark, if it doesn't exist
#
bm(){
  local val=$(pwd)
  for i in ${bookmarks[@]}
  do
     if [ "$i" == "$val" ]
     then
         return 1
     fi
  done
  num=${#bookmarks[@]}
  bookmarks[$num]=$val
}

#
# Goto specified bookmark
# or previous one by default
#
bcd(){
  index=$1
  if [ -z $index ]
  then
      index=$((${#bookmarks[@]}-1))
  fi
  local val=${bookmarks[$index]}
  if [ -z $val ]
  then
      echo "No such bookmark. Type blist to list bookmarks."
      return 1
  else
      cd "$val"
  fi
}

#
# Remove a bookmark
#
brm(){
  if [ $# -lt 1 ]
  then
      echo "Usage: brm <bookmark-index>"
      return 1
  fi
  if [ -z ${bookmarks[$1]} ]
  then
      echo "No such bookmark"
      return 1
  fi
  bookmarks=(${bookmarks[@]:0:$1} ${bookmarks[@]:$(($1 + 1))})
}

#
# Remove all bookmarks
#
bcl(){
    bookmarks=()
}

#
# List all bookmarks
#
bll(){
    if [ ${#bookmarks[@]} -ne 0 ]
    then
        local i=0
        while [ $i -lt ${#bookmarks[@]} ]
        do
            echo $i: ${bookmarks[$i]}
            ((i++))
        done
    fi
    return 0
}

#-------------------------------
# String manipulation functions
#-------------------------------

#
# substring word start [length]
#
substring(){
    if [ $# -lt 2 ]; then
        echo "Usage: substring word start [length]"
        return 1
    fi
    if [ -z $3 ]
    then
        echo ${1:$2}
    else
        echo ${1:$2:$3}
    fi
}

#
# length of string
#
length(){
    if [ $# -ne 1 ]; then
        echo "Usage: length word"
        return 1
    fi
    echo ${#1}
}

#
# Upper-case
#
upper(){
    if [ $# -lt 1 ]; then
        echo "Usage: upper word"
        return 1
    fi
    echo ${@^^}
}

#
# Lower-case
#
lower(){
    if [ $# -lt 1 ]; then
        echo "Usage: lower word"
        return 1
    fi
    echo ${@,,}
}

#
# replace part of string with another
#
replace(){
    if [ $# -ne 3 ]; then
        echo "Usage: replace string substring replacement"
        return 1
    fi
    echo ${1/$2/$3}
}

#
# replace all parts of a string with another
#
replaceAll(){
    if [ $# -ne 3 ]; then
        echo "Usage: replace string substring replacement"
        return 1
    fi
    echo ${1//$2/$3}
}

#
# find index of specified string
#
index(){
    if [ $# -ne 2 ]; then
        echo "Usage: index string substring"
        return 1
    fi
    expr index $1 $2
}

#
# surround string with quotes, for example.
#
surround () {
   if [ $# -ne 2 ]
   then
     echo Usage: surround string surround-with e.g. surround hello \\\"
     return 1
   fi
   echo $1 | sed "s/^/$2/;s/$/$2/" ;
}
If you have any useful functions, please share them in the comments section below.

More posts on my Bash profile:

Friday, March 18, 2011

My Bash Profile - Part III: Completions

Bash programmable completion is a powerful feature which allows you to specify how arguments to commands should be completed. You do this using the complete command. For example, you can set completion up so that when you type the unzip command and hit the TAB key, it only shows completions for files ending with the .zip extension. Similarly, the completion for the ssh command would display hosts taken from your known_hosts file.

The completion file I use can be downloaded from here and saved in ~/.bash_completion. It has a comprehensive range of completions covering commands such as java, cvs, ant, make and kill.

Update: My dotfiles are now in Git. For the latest version, please visit my GitHub dotfiles repository.

One of my favourites is shown below:

_longopt is a generic completion function which can be used to complete the options on a number of different commands. For example, if you type grep --[TAB] you will see the available options for grep.

_longopt()
{
  local cur opt
  cur=${COMP_WORDS[COMP_CWORD]}

  if [[ "$cur" == --*=* ]]; then
      opt=${cur%%=*}
      # cut backslash that gets inserted before '=' sign
      opt=${opt%\\*}
      cur=${cur#*=}
      _filedir
      COMPREPLY=( $( compgen -P "$opt=" -W '${COMPREPLY[@]}' -- $cur))
      return 0
  fi

  if [[ "$cur" == -* ]]; then
      COMPREPLY=( $( $1 --help 2>&1 | sed -e '/--/!d' \
        -e 's/.*\(--[-A-Za-z0-9]\+=\?\).*/\1/' | \
        command grep "^$cur" | sort -u ) )
  fi
}
for i in a2ps autoconf automake bc gprof ld nm objcopy objdump readelf strip \
  bison cpio diff patch enscript cp df dir du ln ls mkfifo mknod mv rm \
  touch vdir awk gperf grep grub indent less m4 sed shar date \
  tee who texindex cat csplit cut expand fmt fold head \
  md5sum nl od paste pr ptx sha1sum sort split tac tail tr unexpand \
  uniq wc ldd bash id irb mkdir rmdir; do
  complete -F _longopt $i
done
Here is a demo:
sharfah@starship:~> grep --[TAB][TAB]
--after-context=       --color                --exclude-from=
--basic-regexp         --colour               --exclude=
--before-context=      --context=             --extended-regexp
--binary               --count                --file=
--binary-files=        --devices=             --files-with-matches
--byte-offset          --directories=         --files-without-match

More posts on my Bash profile:

Friday, March 11, 2011

My Bash Profile - Part II: Aliases

An alias gives you the ability to run a long or cryptic command using a simple name. The syntax is alias name='command' which means that whenever you type name, Bash will substitute command in its place. For example: alias ll='ls -ltr'. You can't use arguments in an alias command. If arguments are needed, a shell function should be used.

To see what aliases are currently defined use the alias command. To disable an alias in your current shell, use unalias name. You can also disable an alias in your current command by prefixing the alias name with a \. For example: \ls.

Update: My dotfiles are now in Git. For the latest version, please visit my GitHub dotfiles repository.

Here is a list of my Bash aliases taken from ~/.bash_aliases

# reloads profile
alias reload='. ~/.bash_profile'

# edit and source aliases file
alias va='vi ~/.bash_aliases; source ~/.bash_aliases && echo "aliases sourced"'

# go up multiple levels
# (also see 'up' function)
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'
alias .....='cd ../../../..'
alias ......='cd ../../../../..'
alias cdhist='dirs -v'

# concise date
alias d='date +%Y%m%d-%H%M'

# various ls shortcuts
alias ls='ls -F --color=auto'
alias l='ls'
alias la='ls -a'
alias ll='ls -ltr'
alias lu='ls -ltur'
alias lal='ls -altr'
alias sl='ls'

# list dirs only
alias ldir='ll -d */'

# less with ignore-case, long-prompt and quit-if-one-screen
alias less='less -iMF'

# more is less
alias more='less'
alias mroe='more'
alias m='more'

alias h='history'

# execute last command
# 'r cc' runs the last command beginning with "cc"
alias r='fc -s'

alias igrep='grep -i'
alias rgrep='grep -r'
alias ftail='tail -f'

# fast scp
alias scp='scp -o StrictHostKeyChecking=no -c arcfour -o Compression=no'

# ps with wide output so you can see full commands
alias fullps='ps -auxwww'

# shows all declared functions
alias functions='declare -F'

# autosys aliases. All start with "job".
alias jobls='autorep -J'
alias jobll='autorep -q -J'
alias jobstart='sendevent -E FORCE_STARTJOB -J'
alias jobhold='sendevent -E JOB_ON_HOLD -J'
alias jobice='sendevent -E JOB_ON_ICE -J'
alias jobkill='sendevent -E KILLJOB -J'
alias joboffhold='sendevent -E JOB_OFF_ICE -J'
alias joboffice='sendevent -E JOB_OFF_ICE -J'
alias jobhist='jobrunhist -j'
alias jobdepends='job_depends -c -J'
alias jobsu='sendevent -E CHANGE_STATUS -s SUCCESS -J'
alias jobterm='sendevent -E CHANGE_STATUS -s TERMINATED -J'
If you have any useful aliases, please share them in the comments section below.

More posts on my Bash profile:

Sunday, March 06, 2011

My Bash Profile - Part I

I wrote about my Bash profile a few years ago and since then I've made a quite a few changes to it such as adding a more powerful prompt and many more useful aliases and functions; some invented, others discovered. Over the next few posts, I will be sharing my current profile with you. Feel free to use and comment, but most importantly share any gems from your own profile that might be useful to the rest of us.

Note that I am using Bash version 4.1.2.

Update: My dotfiles are now in Git. For the latest version, please visit my GitHub dotfiles repository.

.bash_profile
This is executed by Bash for login shells. Quite simply, mine is:

if [ -f ~/.bashrc ]; then
   source ~/.bashrc
fi
.bashrc
This is executed by Bash for interactive non-login shells:
# don't save command history
unset HISTFILE

# don't save duplicates in history
HISTCONTROL=ignoredups

EDITOR=vi
VISUAL=vim
PAGER='less -i'

set -o notify   # Report status of terminated bg jobs immediately
set -o emacs    # emacs-style editing

shopt -s extglob   # extended pattern matching features
shopt -s cdspell   # correct dir spelling errors on cd
shopt -s lithist   # save multi-line commands with newlines
shopt -s autocd    # if a command is a dir name, cd to it
shopt -s checkjobs # print warning if jobs are running on shell exit
shopt -s dirspell  # correct dir spelling errors on completion
shopt -s globstar  # ** matches all files, dirs and subdirs
shopt -s cmdhist   # save multi-line commands in a single hist entry
shopt -s cdable_vars # if cd arg is not a dir, assume it is a var
shopt -s checkwinsize # check the window size after each command
shopt -s no_empty_cmd_completion # don't try to complete empty cmds

# enable coloured 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'
export LESS_TERMCAP_so=$'\E[01;44;33m'
export LESS_TERMCAP_ue=$'\E[0m'
export LESS_TERMCAP_us=$'\E[01;32m'

# define some colours
GREY=$'\033[1;30m'
RED=$'\033[1;31m'
GREEN=$'\033[1;32m'
YELLOW=$'\033[1;33m'
BLUE=$'\033[1;34m'
MAGENTA=$'\033[1;35m'
CYAN=$'\033[1;36m'
WHITE=$'\033[1;37m'
NONE=$'\033[m'

# random grep colour
export GREP_COLOR="1;3$((RANDOM%6+1))"
export GREP_OPTIONS='--color=auto'

# path for directories
export CDPATH=".:..:../..:~/:~/dev/"

# file containing hosts
export HOSTFILE=~/.hosts

# source everything else
. ~/.bash_prompt
. ~/.bash_completion
. ~/.bash_aliases
. ~/.bash_functions

# trap commands to display on the xterm titlebar. Must be last line.
trap 'echo -ne "\033]0;$BASH_COMMAND - $USER@${HOSTNAME}>$(pwd)\007"' DEBUG
Read about my prompt, aliases and functions in the following posts: