Contextual Grepping

One of the tools I find myself using more and more each day is the amazing grep. It helps me narrow down the list of potential problem children in my code. Sometimes it can even tell me exactly where I need to look if my parameters are specific enough.

For example, the other day, I had a problem where some Python code was attempting to call isdigit() on an integer, when the variable was supposed to be a string. I could have scoured the code manually for all occurrences of the word "isdigit", or I could have used a "search in files" sort of feature in any useful text editor. There are likely other options too. However, I opted to use grep to find what I was looking for.

In the process of fixing this bug, I learned that grep offers the option of displaying a few lines of context around your matching text. There are a few ways you can tell grep to give you some context:

  • -A NUM, --after-context=NUM

    Print NUM lines of trailing context after matching lines. Places a line containing -- between contiguous groups of matches.

  • -B NUM, --before-context=NUM

    Print NUM lines of leading context before matching lines. Places a line containing -- between contiguous groups of matches.

  • -C NUM, --context=NUM

    Print NUM lines of output context. Places a line containing -- between contiguous groups of matches.

I thought this was so useful that I wrote a small shell script to wrap up my common options for grepping--recursive search, display line numbers, and (now) showing some context. Eventually I got around to cleaning up the output by dirtying up the script. Cleaning up the output involved only displaying a matching filename one time, with the line numbers for the context and matching lines below it. I also thought it would be easier to find matching lines if I could colorize the matched text. Here's my script as of noon today.

#!/bin/bash
# Recursively greps for some text in files in the current directory with some
# context lines.

GREEN=`echo -e '\033[41;30;1m'`
NORMAL=`echo -e '\033[0m'`
FIND=$1
grep --exclude=*.svn* --exclude=*.swp -rnC 5 "$FIND" * | \
    awk '{split($1, a, "-"); split(a[1], b, ":"); \
    if (b[1] != file) { file=b[1]; print file; } \
    sub(file, "", $0); print $0; }' | \
    sed -e "s/$FIND/$GREEN&$NORMAL/g;s/^[-\:]//g"

I'm sure there are ways to make this more elegant, but I'm sure happy with it. This little dandy assisted me just this morning in helping a friend resolve some Django bugs!

Here's a screenshot:

cgrep script in action

Comments

Comments powered by Disqus

Navigation

Recent Articles

Tag Cloud

adsense  apache  arduino  articles  auto-tagging  bash  bitbucket  blog  breadboard  c  cache  caching  chrome  cisco  command-line  css  database  death  design  desktop  diff  dillon  django  django-articles  django-tracking  documentation  docutils  downtime  driver  easy_install  exec  face-tracking  fedora  feed  firefox  fishing  freelance  fujifilm  git  github  gnome  google  gstreamer  hooks  how-to  howto  html  idiocy  imap4  internet  java  javascript  js  kara  kde  kernel  kurt  lcd  led  linux  logging  mac  macintosh  mail  matt  mercurial  middleware  mindy  mobile  motion  mouse  multiprocessing  network-manager  networking  news  novell  open-source  opencv  opensuse  optimization  osx  packt-publishing  performance  photography  php  picnic  pip  pir  pop3  profile  profiling  programming  projects  pycon  pygments  pypi  python  regex  regular-expression  resistor  rest  restructuredtext  review  rss  ruby  school  scm  scroll  security  sed  selenium  servo  site-wide  slackware  sled  soldering  sparkfun  sphinx  step-by-step  stupid  style  subversion  suse  svn  syndication  templates  terminal  testing  thanks  tips  tornado  tutorial  twitter  unit-testing  unix  updates  utilities  v4l2loopback  vcs  version-control  vim  virtualbox  vista  vpn  web  web-development  webcam  webfaction  windows  wireless  work  wxpython  xorg  xwindows