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:

[bash]mkdir ~/Dropbox/bin[/bash]

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:

[bash]test -r ~/Dropbox/bin/bash_profile && . ~/Dropbox/bin/bash_profile[/bash]

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

[bash]export PATH=~/Dropbox/bin:$PATH[/bash]

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:

[bash]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'[/bash]

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.

[bash]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[/bash]

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.

[bash]export PS1=”[${tRandColor}]u@[${tBold}]h[${tReset}]:[${tBlue}]w[${tReset}] $ “[/bash]

This PS1 variable gives me a prompt like this:

[bash]rob@MBP2:~/Desktop $[/bash]

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:

[bash]
# 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
}[/bash]

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

[bash]label 3 /tmp/*[/bash]

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.

[bash]
# “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
}[/bash]

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

[bash]$ stop safari[/bash]

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

[bash]$ cont safari[/bash]

to fire it up again.

WarningBE 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.

[bash]lsnet(){
lsof -i | awk ‘{printf(“%-14s%-20s%sn”, $10, $1, $9)}’ | sort
}[/bash]

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

[bash] 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[/bash]

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”):

[bash]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
}[/bash]

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

[bash]rn word[/bash]

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:

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

Output looks like this:

[bash]Uptime: 15:49 up 7 days, 3:38, 5 users, load averages: 0.72 0.76 0.65[/bash]

Calendar

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

[bash]if [ “$INTERACTIVETERM” == “-YES-” ]; then
cal | gsed “s/b($(date +%e | sed ‘s/^ *//’))b/${tBold}${tGreen}1${tReset}/”
fi[/bash]

     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:

[bash]if [ “$INTERACTIVETERM” == “-YES-” ]; then
curl –max-time 1 -s ‘http://download.finance.yahoo.com/d/quotes.csv?s=AAPL&f=l1c1p2&#8217; | 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[/bash]

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:

[bash]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
}[/bash]

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.

[bash]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[/bash]

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.
[bash]$ diskstatus[/bash]

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.