Toggle theme

Shell recipes

Here are various bits of scripting that may be useful if you're using a shell like bash or zsh on a Unix-like computer.

Jumping to temporary directories in zsh and bash

Keeping a home directory uncluttered is tough. I often create lists, scripts, or one-off programs I think I may need to refer back to later, but putting them all in a single place quickly becomes unmanageable.

With this function, when I type t, my shell sends me to a $HOME/temp/YYYYMMDD directory for the current date, creating the directory if it doesn't exist. To jump to yesterday's directory or the directory from a week ago, I can run t 1 or t 7 respectively. For longer-term temporary things, I can run t foo to go to $HOME/temp/foo. If I just want to print the directory's name instead of moving to it (suppose that I want to redirect the output from a command to a file), I can run tp or tp foo (the directory will be created first if it doesn't exist).

# switch to temporary directories
temp_dir() {
  local gothere=$1
  local base=$HOME/temp
  local create=1
  if test "$2"; then
    if echo "$2" | egrep -q '^[0-9]+$' && test $2 -gt 0; then
      local dir=$base/$(date -d "$2 days ago" +%Y%m%d)
      local create=0
    else
      local dir="$base/$2"
    fi
  else
    local dir=$base/$(date +%Y%m%d)
  fi

  if [[ $create == 1 ]] && test \! -e "$dir"; then
    mkdir -p "$dir"
  fi

  if [[ $gothere == 1 ]]; then
    cd $dir
  else
    echo $dir
  fi
}
t()  { temp_dir 1 $1; }
tp() { temp_dir 0 $1; }

Setting a custom prompt

This one isn't terribly exciting, but it served me well for the many years that I was using bash:

[user@host][/usr/share]$ ls -la
END="\[\033[0m\]"
BLUE="\[\033[0;34m\]"
YELLOW="\[\033[0;33m\]"
RED="\[\033[0;31m\]"
GREEN="\[\033[0;32m\]"
CYAN="\[\033[0;36m\]"
PURPLE="\[\033[0;35m\]"
BROWN="\[\033[0;33m\]"
L_GRAY="\[\033[0;37m\]"
D_GRAY="\[\033[1;30m\]"
L_BLUE="\[\033[1;34m\]"
L_GREEN="\[\033[1;32m\]"
L_CYAN="\[\033[1;36m\]"
L_RED="\[\033[1;31m\]"
L_PURPLE="\[\033[1;35m\]"
WHITE="\[\033[1;37m\]"

PS1="$D_GRAY[$L_GRAY\u$D_GRAY@$L_GRAY\h$D_GRAY][$L_GRAY\w$D_GRAY]$L_GRAY$ $END"

I'm using zsh instead of bash now, and my prompt looks like this:

[/usr/share] host% ls -la
autoload colors zsh/terminfo
if [[ "$terminfo[colors]" -ge 8 ]]; then
  colors
fi
for color in BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE; do
  eval PR_LIGHT_$color='%{$terminfo[bold]$fg[${(L)color}]%}'
  eval PR_$color='%{$fg[${(L)color}]%}'
  (( count = $count + 1 ))
done
PR_PLAIN="%{$terminfo[sgr0]%}"

PROMPT="$PR_WHITE%m%# $PR_PLAIN"
RPROMPT="${PR_LIGHT_BLACK}[$PR_PLAIN$PR_WHITE%~${PR_LIGHT_BLACK}]$PR_PLAIN"

Setting the window title in bash

When I have many terminal windows open, it's nice to be able to see which is which without having to remember their positions or check their contents.

By echoing special sequences of characters, it's possible to instruct xterm to change its icon name or window title. See the xterm Title HOWTO and the Bash Prompt HOWTO for more details.

When I'm using a terminal emulator that supports it, I can type n foo to change a window's name to foo. Typing n without any parameters switches the title back to the default, user@host. When I use SSH to connect to another host, the window's name is updated appropriately.

Note: If you use a terminal emulator other than xterm, you'll need to update the if statement at the top of this code block. Run echo $TERM to see which value you need to use.

if [ "$TERM" = "xterm" ] || [ "$TERM" = "screen" ]; then
  # make "n" echo escape characters to change xterm's name
  n() {
    if [ -n "$*" ]; then
      PROMPT_COMMAND="echo -ne \"\033]2;$*\007\""
    else
      PROMPT_COMMAND='echo -ne "\033]2;`whoami`@`hostname`\007"'
    fi
  }
  n
  alias_ssh () { echo -ne "\033]2;$*\007"; "ssh" $*; }
  alias ssh=alias_ssh
fi

Custom colors in xterm

This really doesn't have anything to do with shells, but that won't stop me from including it. I put the following in my $HOME/.Xresources file to make xterm's colors a bit more pleasing:

XTerm.*background: black
XTerm.*foreground: white
XTerm.*boldMode:   false
XTerm.*color0:     #000000
XTerm.*color1:     #9e1828
XTerm.*color2:     #4f874f
XTerm.*color3:     #968a38
XTerm.*color4:     #5d5da0
XTerm.*color5:     #963c59
XTerm.*color6:     #418179
XTerm.*color7:     gray
XTerm.*color8:     gray40
XTerm.*color9:     #cf6171
XTerm.*color10:    #c5f779
XTerm.*color11:    #fff796
XTerm.*color12:    #4186be
XTerm.*color13:    #cf9ebe
XTerm.*color14:    #71bebe
XTerm.*color15:    white

I use rxvt-unicode instead of xterm now. To get the same effect there, I replaced the XTerm.* in the above lines with URxvt. and replaced the boldMode line with a URxvt.boldFont line specifying the same font as my URxvt.font.