18

Our source code has error codes scattered throughout. Finding them is easy with grep, but I'd like a bash function find_code that I can execute (eg. find_code ####) which will provide output along these lines:

/home/user/path/to/source.c

85     imagine this is code
86     this is more code
87     {
88         nicely indented
89         errorCode = 1111
90         that's the line that matched!
91         ok this block is ending
92     }
93 }

Here is what I have currently:

find_code()
{
    # "= " included to avoid matching unrelated number series
    # SRCDIR is environment variable, parent dir of all of projects
    FILENAME= grep -r "= ${1}" ${SRCDIR}
    echo ${FILENAME}
    grep -A5 -B5 -r "= ${1}" ${SRCDIR} | sed -e 's/.*\.c\[-:]//g'
}

Problems:

1) This doesn't provide line numbers

2) it only matches .c source files. I'm having trouble getting sed to match .c, .cs, .cpp, and other source files. We do use C, though, so simply matching - or : (the characters that grep appends to the filename before each line of code) matches object->pointers and messes everything up.

4 Answers 4

11

I would change a few things about.

find_code() { 
    # assign all arguments (not just the first ${1}) to MATCH
    # so find_code can be used with multiple arguments:
    #    find_code errorCode
    #    find_code = 1111
    #    find_code errorCode = 1111
    MATCH="$@" 

    # For each file that has a match in it (note I use `-l` to get just the file name
    # that matches, and not the display of the matching part) I.e we get an output of:
    #
    #       srcdir/matching_file.c
    # NOT:
    #       srcdir/matching_file.c:       errorCode = 1111
    #
    grep -lr "$MATCH" ${SRCDIR} | while read file 
    do 
        # echo the filename
        echo ${file}
        # and grep the match in that file (this time using `-h` to suppress the 
        # display of the filename that actually matched, and `-n` to display the 
        # line numbers)
        grep -nh -A5 -B5 "$MATCH" "${file}"
    done 
}
2
  • I adjusted this back to my specifications--I simply want to look up error codes. So MATCH="= ${1}". I also added --include=*.c --include=*.cpp --include=*.java --include=*.cs to limit the search to source files. Thanks! Aug 9, 2013 at 21:53
  • 1
    Good oh, glad you managed to get it fine tuned to your needs :)
    – Drav Sloan
    Aug 9, 2013 at 21:59
3

You could use find with two -execs, the second one will be executed only if the first one is successful, e.g. searching only in .cpp, .c and .cs files:

find_code() {
find ${SRCDIR} -type f \
\( -name \*.cpp -o -name \*.c -o -name \*.cs \) \
-exec grep -l "= ${1}" {} \; -exec grep -n -C5 "= ${1}" {} \;
}

so the first grep prints the filenames that contain your pattern and the second one will print the matching lines+context, numbered, from the respective files.

2

Another option: Git:

git grep --heading xxxxxxxxx

Also respect .gitignore.

Outside of git repo add --no-index.

0

This is a similar, but more robust approach that doesn't require parsing specific flags:

find_code {
    reset="\e[0m"
    purple="\e[35m"

    mapfile -t files < <(grep -l -R "$@" --color=none)
    for fn in "${files[@]}"; do 
        printf "$purple%s$reset\n\n" "$fn"; 
        grep "$@" "$fn"
        printf "\n"
    done
}

However, for the sake of completeness, ripgrep outputs the desired format by default.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .