Tiny Code

Tiny Code

Saturday, March 21, 2015

Command aliases using grep

I keep quite a few command aliases and environment variables which speeds up my use of the command line.  However sometimes it can be difficult to recall exactly what I've called one of the ones I haven't used in a while.  To help with this problem, I find it handy to define a few easy to remember command aliases to help me search my list of command aliases, environment variables, and recent command history.

alias   ag='alias | grep -i'
alias   eg='env | grep -i'
alias   hg='history | grep -i'

The need to search through command aliases and history are probably somewhat obvious.  You may ask why I find the need to keep so many environment variables though.  It turns out they're incredibly handy as shortcuts for frequently used directory paths.

For example, I always keep a shortcut called $DT for my Desktop.  That makes it very easy to move or copy a file to the Desktop using a short command like "cp filename $DT".  It removes the need for me to remember the Desktop path on all the OSes I use on a regular basis (Windows, Linux, and Mac OS X).

That may seem a simplistic use but I also keep environment shortcuts for the paths to all the SDKs (software development kits) and virtual machine shared directories I use.  That frees me up to remember more important things.

Thursday, March 5, 2015

Changing your shell prompt

I find it useful to use a colorful prompt on all the Unix or Unix-like machines I have accounts on.  It makes it much easier to scroll back to find the start of output of previously issued commands.  Otherwise you're wading through a sea of similarly colored text trying to find something which looks like your shell prompt.  That may not seem difficult but when you're dealing with makefiles which can output hundreds of lines of output, you need all the help you can get.

Look at the prompt in the following snippet from my terminal window.  It's very obvious where the prompt is and the date and time stamp in the prompt prove useful quite often.  Note that it's the date and time stamp of the prompt which follows the command output which provides an approximate time of command execution.

Another thing I like to do is to color code my prompts with the level of privileges associated with the account.  Admin accounts get a red background while user level accounts get a nice soothing blue.  You can never have too many reminders of the fact that you're using an admin account.

There are a couple ways to create a prompt like this.  The easiest is to use a handy web site like the .bashrc generator to help you configure your prompt.

I prefer having greater control over my prompt than most tools like the bashrc generator provide and I find too much information in a prompt distracting.  So the following snippet from my .bashrc file does the trick nicely.  You may need this ANSI escape sequence reference to figure out what my prompt is doing.  There are two main parts.  First I'm overriding the text in the terminal window's title bar with "Rods Terminal" followed by the working directory.  Then we jump back into the actual window, change foreground and background colors, and print our prompt.  Finally, we change back to some subdued colors for normal command output.

# Attribute codes:
# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
# Text color codes:
# 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
# Background color codes:
# 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white

PS1='\n\[\e]1;Term ${$} \a\e]2;Rods Terminal ${PWD}\a\
[\D{%m-%d} \t] eh? \[\e[m\] \n'

Sunday, March 1, 2015

Making code reviews easier

Our source trees at work contain quite a few files spread out over many directories.  So reviewing code changes done by other engineers used to present a challenge.  Being handed 10 files to review used to mean manually finding each in the source tree so I could set up my diff tool with the appropriate paths to see what changes had been made to each file.  So I came up with a small bash script to automate the finding of base source files for comparison.

When I receive an e-mail containing source files to review, I copy all the modified source files to a directory called /c/review/new (this directory looks odd because I'm stuck on a Windows machine and run Cygwin to make it easier to use).  Then I cd to the top of a source tree with no changes I keep synched up with our SVN server and I type the name of my script below.  I call it "revcp" for review copy.  It finds and copies files from the current directory into a directory called /c/review/old.  Once that's done, I fire up WinMerge pointing at the old and new directories.

The only thing which can present a problem is that sometimes there are files for review for which there are multiple matches.  Makefiles are a prime example since we have quite a few of them.  The script will find all matches and prompt the user for which file to copy.

Is it perfect?  Not by any stretch of the imagination.  But for a "quick and dirty" tool which only took 15 or 20 minutes to write, it saves me quite a bit of time.  Now I no longer dread the arrival of code review requests.

#   revcp (review copy)
# Description:
#   Given a single directory containing a group of source files to be
#   reviewed, this script will find matching files from the source tree
#   starting at the current directory for comparison.
# One time preparation:
#   1)  Modify NEW_DIR and OLD_DIR environment variables below to specify
#       the directory where you've placed the files to be reviewed and
#       the directory where you'd like the corresponding base files
#       to be copied.
# To use:
#   1)  Copy all files to be reviewed into the directory pointed to by the
#       environment variable NEW_DIR set below
#   2)  cd to a directory in your source tree above all files being reviewed
#       such as /c/svnBase/riot/client (where svnBase is the directory where
#       your svn source tree is checked out).
#   3)  Run this shell script under Cygwin or another Unix shell.
#   4)  If duplicate files are found by script the user will be prompted to
#       choose the desired file.  Once chosen, the script will manually copy
#       the selected file to OLD_DIR.
#   5)  Use WinMerge or another diff utility which can diff entire directories
#       to compare the contents of OLD_DIR with NEW_DIR

# This directory contains new files to review

# Files found from current path will be copied to this directory


function FindMatchingFile
    CurFileName=`basename "$1"`
    NumFiles=`find . -name $CurFileName -print | wc -l`
    if [ $NumFiles -eq 1 ]; then
        echo "Copying $CurFileName"
        find . -name $CurFileName -exec cp {} $OLD_DIR \;
    elif [ $NumFiles -eq 0 ]; then
        echo "File $CurFileName not found... must be new file"
        echo ""
        echo "Found multiple matches for file: $CurFileName"
        echo ""
        MatchingFiles=`find . -name $CurFileName -print`
        for m in $MatchingFiles
            echo "$i - $m"
            let "i=i+1"
        echo ""
        echo -n "Enter number of the file to copy or 0 to skip: "
        read FileNum
        if [ $FileNum -eq 0 ]; then
            echo "Skipping $CurFileName"
        elif [ $FileNum -le $NumFiles ]; then
            for m in $MatchingFiles
                if [ $i -eq $FileNum ]; then
                    echo "Copying file #$i - $m"
                    cp $m $OLD_DIR
                let "i=i+1"
            echo "User input too large"
        echo ""

echo "revcp - copy files for review"
for f in $FILES
    FileNameToFind=`basename "$f"`
    FindMatchingFile $FileNameToFind

Tuesday, February 24, 2015

Changing to a sibling directory easily

I deal with multiple source trees on a daily basis.  Occasionally it's handy to switch from a subdirectory in one to the same subdirectory in a different source tree.  So I put together the following set of shell functions (similar to command aliases but they allow greater flexibility in checking parameters) to make this easier.

For example, let's suppose my current directory is ~/src/tree1/subdir1/subdir2/subdir3/ and I want to switch to the same path in the directory ~/src/tree2.  With these bash functions defined, I can type the command "cds tree1 tree2".  If I want to return to the previous directory, I can hit the up arrow key to recall the command, cursor over, and change the "cds" command to "cdsb".

# cd sideways (replaces one portion of current path with new string and changes to that directory)
function    cds
    if [ -z "$2" ]                           # Is parameter #1 zero length?
        echo "Usage: cds DirPatternToReplace DirNewPattern"
        NWD=`echo $PWD | sed -e "s/$1/$2/"`
        echo "Changing directory"
        echo "from: $PWD"
        echo "to:   $NWD"
        cd $NWD

# cd sideways back (same as previous command but parameters are reversed to go backwards)
function    cdsb
    if [ -z "$2" ]                           # Is parameter #1 zero length?
        echo "Usage: cdsb DirPatternToReplace DirNewPattern"
        NWD=`echo $PWD | sed -e "s/$2/$1/"`
        echo "Changing directory"
        echo "from: $PWD"
        echo "to:   $NWD"
        cd $NWD

Saturday, February 21, 2015

Bash history

I've always had a strong preference for using command lines interfaces (AKA CLIs) over GUIs.  I can get tasks accomplished much faster using a Unix bash shell than I can on any GUI.  Plus CLIs lend themselves to greater levels of customization than GUIs do.  If I can customize a user interface, I can adapt it to the way I prefer doing things which makes the CLI even faster to use.

One of the customizations I use in Unix style shell interfaces is to modify how commands are stored in the shell command history.  I prefer the Bash shell (AKA Bourne Again Shell).  If you don't understand the humor in that, a little time on Google can clear it up for you.

The first step I took is to specify a permanent file for my shell history.  This allows multiple shells to share the same command history which frees me from the need to remember which shell I entered a command of interest into so I can recall it.  The following lines in a .bashrc file will set this for me.

# override default history size and file settings
export HISTSIZE=500
export HISTFILE=~/.bash_history

I also need to prevent my history from being wiped out when a shell is closed.

# prevent closing a shell from overwriting history
shopt -s histappend

I also find it helpful to store timestamps for each command stored in the history.  This can be useful for shared computers where you may not be the only user entering commands.

# Store timestamp information for each command
export HISTTIMEFORMAT="%m%d %T  "

I also hate seeing duplicate commands in my command history.  One of each is sufficient and any more than that just clutter up the history unnecessarily.

# don't store duplicate commands
export HISTCONTROL=ignoredups:erasedups

And last but not least, I hate to waste space in my command history for short commands.  Typing ls is faster than looking it up in the command history so why waste space that could be storing more complicated commands that are harder to remember?

# ignore certain commonly issued commands
export HISTIGNORE=ls:ps:pwd

These lines added to your .bashrc should work on Linux, Cygwin under Windows, or Mac OS X terminal sessions.

Sunday, March 17, 2013

Sharing data

These days I split my computing time between a desktop computer at work, a desktop computer at home, a tablet device, and a smartphone.  Frequently I find myself wanting to save data in the form of a bookmark, a link to a web pace, or a note on one of these devices to access later on others.  Fortunately, there are a number of applications which make this easy.  Here are the applications I've picked to do the job.

Dropbox - Installing this application on computers and mobile devices allows effortless sharing of all types of files between devices.  Dropbox gets used by a number of other applications like PlainTest (listed below) to make life easier.

PlainText - Allows easy viewing and/or editing of text files stored on your Dropbox account from your mobile devices.  Only available on iOS devices like iPhone and iPad but you can find similar applications for Android devices.

Xmarks - Makes keeping bookmarks synchronized between browsers on desktop and laptop computers dead simple.

Instapaper - Ideal for those URLs you stumble upon on an application on one device that you want to save for later viewing.  A number of mobile device applications such as Twitter feature integration with Instapaper to simplify the task of saving interesting web pages.

Saturday, February 9, 2013

Windows development tools

It's no secret that given my own choice, I'd abandon the use of Windows PCs altogether.  However it's a sad fact of life that many of development tools I need to use at work are commercial Windows based tools.  In order to make using a Windows PC on a daily basis more bearable, I add the following tools.  An unmodified Windows PC is almost unusable to me these days.  I've no idea how anyone can get anything done on an unmodified Windows PC.

All of the following tools are free except VMware.

  • 7zip - The best archive utility I've found for Windows.  It handles all the archive formats I need to use like ZIP, RAR, and TGZ.
  • Ack - A handy little Perl script similar but superior to Grep which searches only source files.
  • ctags - Creates tags files which many editors, including Vim, can use to make source code navigation dramatically easier.
  • cygwin - Well worth it for the Unix style shell alone but you can add Windows ports of most Unix tools using this.
  • DropBox - Makes sharing files between multiple systems possible.  I take it one step further and have added it to my phone as well so my files are now easily portable.
  • FeedReader - I'm faced with periodic downtime at work where I have to wait for software builds, downloads, and tests to complete.  This RSS reader allows me to stay up-to-date on development tools and techniques during these intervals.
  • Sumatra PDF reader - Using a less popular PDF reader lowers the chances that you'll fall prey to malware using PDF files as a delivery mechanism.
  • Irfanview - Handy for cropping screenshots and other light image file manipulation.
  • Pidgin - Our office uses IM to stay in touch.  This is a nice little IM program with support for multiple IM protocols.
  • putty - I periodically need to connect to remote systems using telnet or ssh protocols.  This program makes that easy.
  • source navigator - Useful for familiarizing yourself with large bodies of source code.
  • sysinternals - These utilities proved so handy that Microsoft purchased the company which developed them.
  • TeraTerm - A decent terminal emulator.  Handles both telnet and serial port connections but I only use it for its serial capabilities.
  • Thunderbird - I use this to monitor my home email account.
  • TortoiseSvn - Integrates the Subversion source code control system with Windows Explorer.
  • TrueCrypt - A useful program for encrypting files, directories, and disk images.  I use it for some of the files I store on DropBox.
  • VMware - I need to run Linux software occasionally.  VMware is the fastest and easiest method I've found of doing this without using a separate PC. 
  • Winmerge - This is the best visual tool I know of for displaying differences between files and for merging changes from one file to another.
  • winscp - Handy for transferring files between systems using ftp, sftp, or scp protocols.
  • Wireshark - The best Ethernet packet sniffer.  It understands lots of protocols and can be extended to understand new ones if necessary.
  • Vim - My favorite editor.  It's a Vi clone with modern features like color syntax highlighting and column editing.
  • Xvi32 - My favorite hex editor.