Recursive grep'ing with bash

· 3min · Dan F.
Table of Contents

How many times have grep'd a file, and then piped the output in order to grep again, and then piped that again to grep? Sometimes when I am search a file, I could end up piping maybe a dozen times while searching the file. Just for fun, I wanted to write a recursive grep program, rgrep in rust. However, as a first step, I figured I could write it in bash first.

In order to use associated arrays, you must first be using Bash 4, as earlier versions did not have this feature. I wrote this as simply as possible, so there very well could be bugs. I only wanted to write as lean a script as possible for preliminary testing.

rgrep.sh

#!/usr/bin/env bash

# Initialize array for search results
declare -A rloop

# Get array of args
args=($@)

# Get length of args array
arg_len=${#args[@]}

# Exit if too few args are passed
if [[ $arg_len -le 1 ]]
then
    echo "Please enter your args, followed by a trailing file to parse"
    exit 1
fi

# Get last arg
file=${args[$len-1]}

# Exit if $file does not exist
if [[ ! -e $file ]]
then
    echo "Could not access $file"
    exit 1
fi

# Get list of args ignoring the last arg
search_terms=${args[@]:0:${arg_len}-1}

# Loop over args
count=0
for i in ${search_terms[@]}
do
    if [[ $count == 0 ]]
    then
        # If we are on the first loop, then grep the file directly
        rloop[$count]=$(grep -i $i $file)
    else
        # Otherwise, grep the previous loop's content
        previous_loop=$((count-1))
        rloop[$count]=$(echo "${rloop[$previous_loop]}" | grep -i $i)
    fi
    count=$((count+1))
done

# Display search results
last_loop=$((count-1))
echo "${rloop[$last_loop]}"

Just for a example of how this script works, create a file called poem.txt with this text:

Shall I compare thee to a summer's day?
Thou art more lovely and more temperate.
Rough winds do shake the darling buds of May,
And summer's lease hath all too short a date.
Sometime too hot the eye of heaven shines,
And often is his gold complexion dimmed,
And every fair from fair sometime declines,
By chance, or nature's changing course untrimmed.

Using rgrep.sh, we can search for lines that include the work "and":

[admin@openbox coding_projects/shell]# ./rgrep.sh and poem.txt
Thou art more lovely and more temperate.
And summer's lease hath all too short a date.
And often is his gold complexion dimmed,
And every fair from fair sometime declines,

Here, we can then search for lines that include "and" as well as "fair":

[admin@openbox coding_projects/shell]# ./rgrep.sh and fair poem.txt
And every fair from fair sometime declines,

This is just a simple implementation of a recursive grep. Next will be me trying to find a way to code this shell script in rust. Hopefully someone will find a use for this code.


Has been tested on OpenBSD 6.5