Home > Utility > Bash Profile Sharing and Useful Scripts

Bash Profile Sharing and Useful Scripts

If you live at the command line as I do, you probably have a number of aliases, functions, and status updates added to your ~/.bash_profile, ~/.bashrc, or similar file. With a little effort you can share the critical components across several computers either automatically (Dropbox or SugarSync) or manually. The key is to abstract away machine-specific references. The following are suggestions for useful additions to your command line lifestyle.


Sharing

If you haven’t explored Dropbox or SugarSync yet, you probably should. It’s what Apple’s iDisk is supposed to be, except that Apple’s iDisk is unreliable and slow, where as the Dropbox and SugarSync guys have figured it out.

First I create a bin folder on my Dropbox:

mkdir ~/Dropbox/bin

as a repository for my new ~/Dropbox/bin/bash_profile script as well as sundry scripts and command line apps that I want to share, such as my LocateMe app for finding my latitude and longitude.

Inside my ~/.bash_profile script, near the top, I check for and include the Dropbox file:

test -r ~/Dropbox/bin/bash_profile && . ~/Dropbox/bin/bash_profile

Of course one of the first things I do in the Dropbox file is add bin to my PATH:

export PATH=~/Dropbox/bin:$PATH

Even if you don’t use Dropbox, having most of your bash environment set up in a separate file makes it easy to copy from machine to machine and keep your customizations readily accessible.

Aliases

In my bash profiles I put aliases, very simple command substitutions or expansions. Here are some of the alias commands I put in my Dropbox bash_profile file:

alias cl='clear; ls -lhG'
alias cla='clear; ls -lhAG'
alias l='ls -lhG'
alias la='ls -lhAG'
alias ls="ls -G"
function cd { pushd "$@" 2>&1 > /dev/null; }
function cdl { cd $1; ls;}
function mcd { mkdir "$1"; cd "$1"; }
alias pg='ps axw | grep -i'
alias plg='port list | grep -i'

Many of these you’ll find on other sites that suggest useful aliases, but in summary, I have various shortcuts for listing directory contents by clearing the screen first (‘c’) and in color, keeping track of current directory changes (OK, those are functions not aliases, but they’re awfully short), and searching for running processes or programs I’d like to install. I have others (not shown) for making common SSH connections and other things.

Of course I use directory listings pretty much continuously, but I find that I use pg to search for running processes quite a bit too. That’s a good one, in my book.

Colors

Before I get into functions and status updates, I want to be able to sprinkle my terminal with useful color using tput commands and ANSI escape sequences. Because of a number of other ways in which I interact with the shell, such as DTerm, the awesomest tiny tool I’ve come across in a long time, I need to know if the bash_profile script is running in some kind of interactive way (Terminal.app) or something else. This is because tput barfs if there’s no proper TERM variable set, so before I define colors, I make a way to detect interactivity.

INTERACTIVETERM=-YES-
if [ "$TERM" == "" ]; then INTERACTIVETERM="-NO-"; TERM="vt100"; fi
if [ "$TERM" == "dumb" ]; then INTERACTIVETERM="-NO-"; TERM="vt100"; fi
export INTERACTIVETERM

# Set up TPUT color codes
if [ "$INTERACTIVETERM" == "-YES-" ]; then
  tReset="$(tput sgr0)"
  tBold="$(tput bold)"
  tBlack="$(tput setaf 0)"
  tRed="$(tput setaf 1)"
  tGreen="$(tput setaf 2)"
  tYellow="$(tput setaf 3)"
  tBlue="$(tput setaf 4)"
  tPink="$(tput setaf 5)"
  tCyan="$(tput setaf 6)"
  tGray="$(tput setaf 7)"
  tWhite="$(tput setaf 8)"
  TUNON="$(tput smul)"
  TUNOFF="$(tput rmul)"
  tRandColor="$(tput setaf $(( $(hostname | openssl sha1 | sed 's/.*\([0-9]\).*/\1/') % 6 + 1 )) )"
else
  tReset=
  tBold=
  tBlack=
  tRed=
  tGreen=
  tYellow=
  tBlue=
  tPink=
  tCyan=
  tGray=
  tWhite=
  tUndOn=
  tUndOff=
  tRandColor=
fi

I have the big if/then statement so that I can embed these variables, and if colors are supposed to be ignored, the variables will simply be empty. Frankly, I don’t know if I have to have all these empty “set” statements, but it seems like good form.

The tRandColor variable gives me a color based on the hostname of the system. I use it to create a default shell prompt that has a good chance of being an unexpected color when I SSH onto another system. That said, the PS1 variable is one that I usually override and specify manually in ~/.bash_profile.

export PS1="\[${tRandColor}\]\u@\[${tBold}\]\h\[${tReset}\]:\[${tBlue}\]\w\[${tReset}\] \$ "

This PS1 variable gives me a prompt like this:

<span style="color:green">rob@<span style="font-weight:bold">MBP2</span></span>:<span style="color:blue; font-weight:bold">~/Desktop</span> $

The extra backslashes and square brackets \[…\] are necessary so that the color codes are not counted as printed characters when counting columns. Without them the text wraps incorrectly when you cd to a long or deeply-nested directory name.

Functions

Shell functions give me more control than an alias. They could certainly each be their own shell script in the bin directory, but…they’re not. Whatever you want.

Set Label Colors in the Finder

The Mac Finder has the concept of “labels” which used to, and may still, have text associated with them, but I only use them to color the background of files in the Finder. Sometimes I want to bridge the gap from command line to the Finder, usually when I’m processing files and want to indicate which ones have been processed. Here’s a handy script for changing the Finder label colors from the command line:

# Set Finder label color
label(){
  if [ $# -lt 2 ]; then
    echo "USAGE: label [0-7] file1 [file2] ..."
    echo "Sets the Finder label (color) for files"
    echo "Default colors:"
    echo " 0  No color"
    echo " 1  Orange"
    echo " 2  Red"
    echo " 3  Yellow"
    echo " 4  Blue"
    echo " 5  Purple"
    echo " 6  Green"
    echo " 7  Gray"
  else
    osascript - "$@" << EOF
    on run argv
        set labelIndex to (item 1 of argv as number)
        repeat with i from 2 to (count of argv)
          try
            tell application "Finder"
                set theFile to POSIX file (item i of argv) as alias
                set label index of theFile to labelIndex
            end tell
          on error
          end try
        end repeat
    end run
EOF
  fi
}&#91;/bash&#93;

This changes the colors of files in <tt>/tmp</tt> (for which I have permissions) to yellow (pointlessly):

[bash]label 3 /tmp/*

Stop and Continue

Sometimes (even on a Mac) an app runs away and hogs all the resources, so I like to be able to -STOP and -CONT a process with the kill command. Stopping a process in this way immediately arrests its forward motion. You’ll notice the spinning beach ball of death over any windows belonging to that application.

# "stop" a process
stop(){
  if [ $# -ne 1 ]; then
          echo 1>&2 Usage: stop process
  else
    PROCESS=$1
    echo "Stopping processes with the word ${tGreen}$1${tReset}"
    ps axw | grep -i $1 | awk -v PROC="$1" '{print $1}' | xargs kill -STOP
  fi
}


# "cont"inue a process
cont(){
  if [ $# -ne 1 ]; then
          echo 1>&2 Usage: cont process
  else
    PROCESS=$1
    echo "Continuing processes with the word ${tGreen}$1${tReset}"
    ps axw | grep -i $1 | awk -v PROC="$1" '{print $1}' | xargs kill -CONT
  fi
}

So if Safari is going wonkers (probably due to Flash of course), you can execute

$ stop safari

to give your computer a break until you figure out what to do next. Later use

$ cont safari

to fire it up again.

Warning

BE CAREFUL what arguments you give stop since it will match any portion of the command. Typing stop e will probably give you a very bad day.

List Network Connections

OK this is basically a one-liner too, but it lists network connections using netstat, cutting out the fluff, and rearranging some columns.

lsnet(){ 
        lsof -i  | awk '{printf("%-14s%-20s%s\n", $10, $1, $9)}' | sort 
}

Looks like this (I cut out lines because it’s long and doesn’t help you any):

              COMMAND             NAME
              Dropbox             *:17500
              SystemUIS           *:*
              SystemUIS           *:*
              eapolclie           *:*
(CLOSED)      Dropbox             *:*
(CLOSED)      Dropbox             *:*
(CLOSED)      Finder              172.20.81.67:52283->configuration.apple.com:https
(CLOSED)      Mail                172.20.81.67:53459->iw-in-f109.1e100.net:imaps
(CLOSED)      Safari              172.20.81.67:52554->198.107.147.23:https
(CLOSED)      Safari              172.20.81.67:52569->projects.sourceforge.net:http
...
...
(CLOSE_WAIT)  Safari              172.20.81.67:53679->pages.github.com:http
(CLOSE_WAIT)  iPhoto              172.20.81.67:50255->a96-7-4-158.deploy.akamaitechnologies.com:https
(CLOSE_WAIT)  webdavfs_           172.20.81.67:52288->a96-7-13-206.deploy.akamaitechnologies.com:https
(CLOSE_WAIT)  webdavfs_           172.20.81.67:52289->a96-7-13-206.deploy.akamaitechnologies.com:https
(CLOSE_WAIT)  webdavfs_           172.20.81.67:52290->a96-7-13-206.deploy.akamaitechnologies.com:https
(ESTABLISHED) Dropbox             172.20.81.67:60975->208.43.202.41-static.reverse.softlayer.com:http
(ESTABLISHED) Dropbox             localhost:26164->localhost:49200
(ESTABLISHED) Finder              localhost:49200->localhost:26164
(ESTABLISHED) Mail                10.42.23.104:57250->pw-in-f109.1e100.net:imaps
...
(ESTABLISHED) Safari              172.20.81.67:52852->172.20.20.66:https
(ESTABLISHED) Safari              172.20.81.67:53781->pw-in-f113.1e100.net:http
...
(ESTABLISHED) SystemUIS           localhost:60727->localhost:5204
(ESTABLISHED) SystemUIS           localhost:60728->localhost:5204
(ESTABLISHED) servernot           172.20.81.67:53795->nwk-st-courier026-08.push.apple.com:https
(ESTABLISHED) webdavfs_           172.20.81.67:53330->a96-6-141-206.deploy.akamaitechnologies.com:https
(LISTEN)      Dropbox             *:17500
(LISTEN)      Dropbox             localhost:26164
(TIME_WAIT)   Cyberduck           localhost:52464->localhost:52463
(TIME_WAIT)   Safari              localhost:62748->localhost:62747

Renice

Here’s another favorite: a process is being a hog, so I want to “renice” it to give it lower priority (technically, a higher “niceness”):

rn()
{
  ps ax | grep -i "${1}" | awk ' \
  $0 !~ /grep/ { count++; pids[count] = $1} \
  END { \
    for( idx in pids ) print " +5", pids[idx]; \
  }' | xargs renice -n 
}

And now I can make Microsoft Word a bit more well-mannered:

rn word

Reporting

Next I have some reporting that, if I’m in an interactive shell such as Terminal.app, will give me some info with each Terminal window I open. Sometimes I thin this out. Sometimes I make it longer. Here are some handy bits:

Uptime

The uptime command is easy enough on its own, but I like to color code the important parts:

if [ "$INTERACTIVETERM" == "-YES-" ]; then
  echo "Uptime: " $(uptime | sed "s/up \([0-9a-zA-Z: ]*\),/up ${tBlue}${tBold}\1${tReset},/")
fi

Output looks like this:

Uptime:  15:49 up <span style="color: blue;font-weight:bold">7 days</span>, 3:38, 5 users, load averages: 0.72 0.76 0.65

Calendar

To help me with context, I display the month’s calendar and draw attention to the current day of the month:

if [ "$INTERACTIVETERM" == "-YES-" ]; then
  cal | gsed "s/\b\($(date +%e | sed 's/^ *//')\)\b/${tBold}${tGreen}\1${tReset}/"
fi
     March 2011
Su Mo Tu We Th Fr Sa
       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

Stock Ticker

To help me feel good about the Apple stock I bought at $130/sh I have a quick stock ticker:

if [ "$INTERACTIVETERM" == "-YES-" ]; then
  curl --max-time 1 -s 'http://download.finance.yahoo.com/d/quotes.csv?s=AAPL&f=l1c1p2'  | awk -F, -v tBold="$tBold" -v tReset="$tReset" -v tColor="$tGreen" '{ printf("AAPL: %s%s\$%s%s, %s∆ \n", tBold,tColor,$1,tReset, $2) }'
fi
AAPL: $338.28, +8.27∆

(In case the character following the price change doesn’t come through on your computer, it’s a triangle/delta symbol.)

You might want to abstract this a step further and make it a function. In fact, I’ll update my scripts right now:

stock(){
  if [ $# -lt 1 ]; then
          echo 1>&2 Usage: stock symbol1 [symbol2] [...]
  else
    while [ "$1" ]; do
      STOCK="$(echo $1 | tr 'a-z' 'A-Z')"
      curl --max-time 1 -s "http://download.finance.yahoo.com/d/quotes.csv?f=l1c1p2&s=${STOCK}"  | \
        awk -F, -v stock="$STOCK" -v tBold="$tBold" -v tReset="$tReset" -v tColor="$tGreen" \
        '{ printf("%s: %s%s\$%s%s, %s∆ \n", stock,tBold,tColor,$1,tReset, $2) }'
      shift
    done
  fi
}

Battery Status

Another cool one: this gives me the estimated battery life remaining. Yeah, I could look it my menu bar to see that, but it’s way “up there” in the menu bar. I can’t be bothered with that.

if [ "$INTERACTIVETERM" == "-YES-" ]; then
MINREM=`ioreg -l | grep AvgTimeToEmpty | cut -d= -f 2`
if [ "$MINREM" = "" ]; then
  # No battery? Maybe a desktop computer
  # Do nothing
  echo 
elif [ $MINREM -gt 60 ]; then 
  HRREM=$((MINREM / 60))
  MREM=`expr $MINREM % 60`
  echo Battery: ${tGreen}${tBold}$HRREM hr $MREM min ${tReset} remaining
else
  if [ $MINREM -lt 20 ]; then
    COLOR=$tRed
  else
    COLOR=$tGreen
  fi
  echo "Battery: $COLOR${tBold} $MINREM min ${tReset} remaining"
fi
fi
Battery: 3 hr 9 min  remaining

Added 11 April 2011. Here’s another handy script for displaying a quick summary of your attached disks. I made this a separate file from my bash_profile since it’s a bit longer than these other functions, but here’s what the diskstatus output looks like.

$ diskstatus
Volume            Usage   Size   Used  Avail
Macintosh HD        67%  931Gi  618Gi  313Gi
TimeMachine1TB      95%  931Gi  876Gi   55Gi
Extra930            42%  931Gi  386Gi  545Gi

Conclusion

Make your command line time more rewarding. Sync your scripts with Dropbox or at least make a separate file that is machine-agnostic that’s easy to copy from machine to machine.

Categories: Utility Tags: , , ,
  1. Teemu Karppinen
    October 20th, 2011 at 06:22 | #1

    Thanks for the scripts and the Dropbox tip. 🙂 I have little difficulties running these scripts since my terminal is missing some commands, I guess. I get the following info when I log in to my SSH server on Mac Mini.

    Uptime: 15:16 up 5 days, 17:55, 4 users, load averages: 0.03 0.07 0.07
    -bash: gsed: command not found
    -bash: gawk: command not found
    -bash: gsed: command not found

    Can you tell me how I should get gawk & gsed? Are these commands in your aliases or should I download and install them?

  2. October 24th, 2011 at 22:55 | #2

    @Teemu Oh, those must have been added later with MacPorts. Try http://www.macports.org and install that. Then from the command line try something like

    sudo port install gsed gawk

  1. October 10th, 2014 at 09:07 | #1
  2. October 15th, 2014 at 12:10 | #2
  3. November 14th, 2014 at 17:34 | #3