Over time the *NIX user gradually grows an individualized collection of shell scripts, aliases, functions, and variable settings sufficiently idiosyncratic and obscure that no other user can navigate his system. Security through idiosyncrasy. I, alas, am somewhat allergic to the shell: our blossoming symbiosis will likely never be complete. However, I am proud of a few tricks I keep in my ~/.profile
which I will share with you today.
Since I regularly use more than one computer, it’s important to keep the .profile
up to date. For this purpose, I naturally use Dropbox.
> ln -s Dropbox/Preferences/tilde-slash/dot-profile .profile
System synchronization is just a symbolic link away. Let’s check out my .profile
starting at the top.
Fortune
## Print the Fortune
# -- Too much of a distraction.
#echo
#/sw/bin/fortune
#echo
I commented this out ages ago. I haven’t used Fink in years, had to look up what sw
stood for. When I was a child, I remember my father liked to see a fortune when he would login to the computer at AT&T using a green screened terminal.
These days I want my startup nice and clean. So I
> touch .hushlogin
Prompt
## Reduce the prompt to just the working directory
PS1="\W> "
Some people like it fancy. I like it uncluttered, but with enough context to keep me straight. For a long time, I used \w
(lowercase) for the full path . Seeing the full path became troublesome when it filled most of the line, resulting on unseemly line wrap for regular commands. Keep it short, sweet, and out of the way.
I don’t know when, where, or why I picked >
over the more conventional $
.
CDPATH
## Enables CD to easily jump up many levels.
CDPATH=.:..:../..:../../..:~/Dropbox
Another trick from my father. I don’t take advantage of it nearly enough. Suppose you’re navigating a project tree. Consider Rails: instead of
models> cd ../../db
db>
don’t sweat the double dots:
models> cd db
/Users/wtaysom/Desktop/rails-example/db
db>
It’s that easy.
PATH
## Typical PATH: includes mysql
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/mysql/bin:$PATH
One’s path can never be too long. I add more further down.
Tab Completion
## Tab completion
bind '"\t":menu-complete'
By default, tabbing will complete if there’s a unique match. If not, then by pressing tab again, you’ll see you a list of files matching the current prefix. In contrast, menu-complete
allows you to cycle through options, a more helpful behavior in my opinion.
cd Magic
After I cd, I often ls to see what’s around. By setting PROMPT_COMMAND
, I have the shell automatically list the most recently modified files when I change directories. I also store the directory in ~/.lastdir
, so that new terminal windows will automatically to the directory where I’ve been working. Hugely helpful.
## List recent files on directory change and switch to last directory on login.
# Adapted from <http://matt.might.net/articles/console-hacks-exploiting-frequency/>.
# Change to most recently used directory:
if [ -f ~/.lastdir ]; then
cd "`cat ~/.lastdir`"
fi
export LASTDIR="/"
function prompt_command {
# Remember where we are.
pwd > ~/.lastdir
# Record new directory on change.
newdir=`pwd`
if [ ! "$LASTDIR" = "$newdir" ]; then
# List contents.
ls -t -C | head -2
fi
export LASTDIR=$newdir
}
export PROMPT_COMMAND="prompt_command"
cdf Finder Integration
It’s easy to open the current directory in Finder:
> open .
This little gem allows us to go the other way:
## To change directory to the one set in the last opened finder.
cdf() {
currFolderPath=$( /usr/bin/osascript <<" EOT"
tell application "Finder"
try
set currFolder to (folder of the front window as alias)
on error
set currFolder to (path to desktop folder as alias)
end try
POSIX path of currFolder
end tell
EOT
)
echo "cd to \"$currFolderPath\""
cd "$currFolderPath"
}
You can also drag file icons onto the Terminal to paste their path; however, it isn’t too good for cding. Compare:
- Switch to Terminal.
- Type ”
cd
”. - Switch to Finder.
- Drag file from Finder.
- Drop on Terminal.
- Switch to Terminal.
- Type return.
verses:
- Switch to Terminal.
- Type ”
cdf
” and return.
Searching and Counting
Sometimes I want to get a quick overview of project. How big is it? How much profanity is in the comments? That sort of thing.
## Standard search functions / macros
alias e="open -a SubEthaEdit "
alias m="mate"
alias c="open -a Xcode "
sources() {
find -E . -regex '.*[.](h|m|c|cc|java|lisp|cs|rb|js|xul|xml|as|lua|txt)$'
}
todo() {
sources | xargs grep -s "!!"
}
notes() {
sources | xargs grep -s "//!"
}
f() {
sources | xargs grep -si "$1"
}
fc() {
sources | xargs grep -si "$1" | wc -l
}
count() {
sources | xargs wc
}
fs_usage Note
The next line is just reminder.
# Remember: `sudo fs_usage` will tell you what IO is going on.
Always good to keep in mind.
Formatted man pages
The small fixed-width font appropriate for terminal commands doesn’t cut it when you want to try to under carefully understand a man page. When it’s time to read, format as PDF.
## Preview man page as PDF.
manp () {
man -t "${1}" | open -f -a /Applications/Preview.app
}
ls Utils
Self explanatory.
## ls utils
alias lh='ls -a | egrep "^."' # Hidden Files
alias ll='ls -l' # Details
lh
is new to me, haven’t committed it to memory yet. It’s annoying that ls .*
provides more info than one would usually want.
Git Utils
Still new to Git, I’ve only collected one:
## For Git
alias gita='git commit --amend -a'
For SVN
More experience, more shims.
## For SVN
export JAVA_HOME=/Library/Java/Home
LC_CTYPE=en_US.UTF-8
# Usually used for `svn propedit svn:ignore`.
SVN_EDITOR=vi
# adds all the files and directories below the current director into svn
svnadd() {
svn status | grep "^\?" | awk '{print $2}' | xargs svn add
}
# removes all .svn directories
svnrmdirs() {
find . -name .svn -print0 | xargs -0 rm -rf
}
# commits a tagged version
svntag() {
svn cp trunk tags/$1; svn commit -m "tag it"
}
# for ignoring
# useage:
# > svnignore "$file_pattern" $containing_directory
# example:
# > svnignore "build" .
alias svnignore='svn propset svn:ignore'
I use svnadd
and svnignore
the most.
Odds and Ends
The rest hardly deserve any note. Half of them I don’t even use. Though let me tell you that rlwrap
is great little utility. Gives lame command line utilities (often written in Java), the readline finesse we expect from power tools.
## For Rhino JavaScript
### Disabled in order to use SpiderMonkey at /usr/local/spidermonkey/bin/js
#alias js='rlwrap java -cp ~/Other/JavaScript/rhino1_6R7/js.jar org.mozilla.javascript.tools.shell.Main -opt -2'
alias js='rlwrap js'
## For JRuby
PATH=$PATH:~/Other/jruby-1.1b1/bin/
alias jrgem='~/Other/jruby-1.1b1/bin/gem'
alias jrails='~/Other/jruby-1.1b1/bin/rails'
## For CouchDB <http://wiki.apache.org/couchdb/Installing_on_OSX>
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/usr/local/spidermonkey/lib
## For Flex
mflex() {
m /Applications/Adobe\ Flash\ Builder\ 4/sdks/4.0.0/frameworks/projects
}
PATH=$PATH:/Applications/Adobe\ Flash\ Builder\ Beta/sdks/4.0.0/bin
alias cdflashlog='cd ~/Library/Preferences/Macromedia/"Flash Player"/Logs'
## For MacPorts
export PATH=/opt/local/bin:/opt/local/sbin:$PATH
export DISPLAY=:0.0
## For SISC
PATH=$PATH:~/Other/sisc-1.16.6/sisc
## JUnit
JUNIT_HOME="/Users/wtaysom/Other/junit4.5"
CLASSPATH="$CLASSPATH:$JUNIT_HOME/junit-4.5.jar:$JUNIT_HOME"
## For SSHKeychain
SSH_AUTH_SOCK=/tmp/502/SSHKeychain.socket
Final Notes
######### After Everything Else #########
## Have `.` take precedence and `..` have low precedence.
PATH=.:$PATH:..
Yes, I actually do use the ..
PATH
a lot.
Next Time?
Command-line tools.