Grep Love + Less Love

Some grep things that I found handy:

man grep

Seriously. So yummy.

Some handy things that I’m using right now.

-A, -B, -C
print an arbitrary number of lines After, Before, or Before/After the matched string line. Super cool.

–no-filename, -h
Handy when you’re doing an grep -r but you expect 1 file to result. It can turn slop this like this:

bazz@blade72[pts/1][~] grep -r -C 10 "struct as {" /usr/include
/usr/include/vm/as.h- * operation.  Some segment drivers use the address space lock to protect
/usr/include/vm/as.h- * some or all of their segment private data, provided the version of
/usr/include/vm/as.h- * "a_lock" (read vs. write) is consistent with the use of the data.
/usr/include/vm/as.h- *
/usr/include/vm/as.h- * The following fields are protected by the hat layer lock:
/usr/include/vm/as.h- *
/usr/include/vm/as.h- * a_vbits
/usr/include/vm/as.h- * a_hat
/usr/include/vm/as.h- * a_hrm
/usr/include/vm/as.h- */
/usr/include/vm/as.h:struct as {
/usr/include/vm/as.h-   kmutex_t a_contents;    /* protect certain fields in the structure */
/usr/include/vm/as.h-   uchar_t  a_flags;       /* as attributes */
/usr/include/vm/as.h-   uchar_t a_vbits;        /* used for collecting statistics */
/usr/include/vm/as.h-   kcondvar_t a_cv;        /* used by as_rangelock */
/usr/include/vm/as.h-   struct  hat *a_hat;     /* hat structure */
/usr/include/vm/as.h-   struct  hrmstat *a_hrm; /* ref and mod bits */
/usr/include/vm/as.h-   caddr_t a_userlimit;    /* highest allowable address in this as */
/usr/include/vm/as.h-   union {
/usr/include/vm/as.h-           struct seg *seglast;    /* last segment hit on the addr space */
/usr/include/vm/as.h-           ssl_spath *spath;       /* last search path in seg skiplist */

into this

bazz@blade72[pts/1][~] grep -h -r -C 10 "struct as {" /usr/include
 * operation.  Some segment drivers use the address space lock to protect
 * some or all of their segment private data, provided the version of
 * "a_lock" (read vs. write) is consistent with the use of the data.
 *
 * The following fields are protected by the hat layer lock:
 *
 *      a_vbits
 *      a_hat
 *      a_hrm
 */
struct as {
        kmutex_t a_contents;    /* protect certain fields in the structure */
        uchar_t  a_flags;       /* as attributes */
        uchar_t a_vbits;        /* used for collecting statistics */
        kcondvar_t a_cv;        /* used by as_rangelock */
        struct  hat *a_hat;     /* hat structure */
        struct  hrmstat *a_hrm; /* ref and mod bits */
        caddr_t a_userlimit;    /* highest allowable address in this as */
        union {
                struct seg *seglast;    /* last segment hit on the addr space */
                ssl_spath *spath;       /* last search path in seg skiplist */

Ironically I think the first one looks better on the blog, but in the terminal, 2nd one is def preferred.

–with-filename, -H
forces inclusion of filename in result. In the case that you’re supporting grep that can find results for either one file itself and also more files (a flexible script), and you want to parse that grep result, you can use this to force consistency between the grep result for one file and for many files.

-n
Show line numbers

-r
recursive grep search. SUPER USEFUL

When I use -r -H -n together, grep gives a colon-delimeted grep output

filename:line#:matched-line

You can use cut to work with this. ie | cut -f2 -d: to grab the line#

Other important notes
environment variables can take results with newlines on them, it’s just that in order to process that you need to make sure you embed that $var inside quotes “$var” or it will be instead interpreted as all spaces for new lines.

tail +$linenum $filename | head -n $endlinenum | tee /tmp/struct

This in english: I want to print from line $linenum and only print $endlinenum lines. Send this output to a file /tmp/struct and to stdout.

Looking for the struct in /usr/include

[pts/3][~] grep -r "struct as {" /usr/include
/usr/include/vm/as.h:struct as {

Notice that we have here a colon delimited filename:line match
Although we did a recursive search we don’t expect to find more than 1 match.

I would really like to be able to query the whole struct, and here’s how I can do that:
this will find the file, and “less” it at the exact position of the struct.

Note: cool command while using less: the { and } keys will bring you to the matching end and beginning curly brace respectively. { -> goto matching end brace } -> goto matching beginning brace

Note: I just slapped this together and I’m willing to share but take note that my comments below are in-dev comments and may not even make sense or apply to you or the script at all. Nope not taking ’em out :P

#!/home/bazz/tools/bin/bash
# struct finder
# does not yet support multiple file search results
# example usage: ./derp /usr/include "struct as {"

if [ "$1" = "" ]; then
  echo "usage: `basename $0` [dir] [search-str]"
  exit 1
fi


# this needs to come out of var, into xargs invocation
grepline="`grep --with-filename -n -r \"$2\" \"$1\"`"
# /usr/include/vm/as.h:113:struct as {
#echo "$grepline"

wcount="`wc -l <<< \"$grepline\"`"
# wc puts whitespace into the output so we remove that
wc=${wcount//[[:blank:]]/}

#echo "$wc"
if [ "$wc" -gt "1" ]; then
  echo 'Be more specific'
  exit 2
fi
# xargs will invoke this downwards as a function
filename="`echo $grepline | cut -f1 -d:`"
linenum="`echo $grepline | cut -f2 -d:`"

less +$linenum $filename
exit 0


>&2 echo "filename = $filename"
>&2 echo "linenum = $linenum"
endlinenums="`tail +$linenum $filename | grep -n '};'`"
wordcount="`wc -w <<<$endlinenums`"
wc=${wordcount//[[:blank:]]/}
>&2 echo "$endlinenums"
>&2 echo "$wc"

for i in `seq 1 $wc`; do
  cur="`cut -f$i -d' ' <<<$endlinenums`"
  #echo "$cur"
  endlinenum="`cut -f1 -d: <<< $cur`"
  #echo $endlinenum
  #linediff=$(( endlinenum - linenum ))
  #echo "linediff = $linediff"
  tail +$linenum $filename | head -n $endlinenum | tee /tmp/struct
  >&2 printf "is that right? (y/n): "
  read -n1 yn
  echo
  if [ "$yn" == "y" ]; then
    echo 'saved in /tmp/struct'
    exit 0
  fi
done

echo 'we failed :('
exit 1

 

Leave a Reply

Your email address will not be published. Required fields are marked *

*