views:

228

answers:

2

I'm trying to write a script that searches a directory for files and greps for a pattern. Something similar to the below except the find expression is much more complicated (excludes particular directories and files).

#!/bin/bash
if [ -d "${!#}" ]
then
    path=${!#}
else
    path="."
fi

find $path -print0 | xargs -0 grep "$@"

Obviously, the above doesn't work because "$@" still contains the path. I've tried variants of building up an argument list by iterating over all the arguments to exclude path such as

args=${@%$path}
find $path -print0 | xargs -0 grep "$path"

or

whitespace="[[:space:]]"
args=""
for i in "${@%$path}"
do
    # handle the NULL case
    if [ ! "$i" ]
    then
        continue
    # quote any arguments containing white-space
    elif [[ $i =~ $whitespace ]]
    then
        args="$args \"$i\""
    else
        args="$args $i"
    fi
done

find $path -print0 | xargs -0 grep --color "$args"

but these fail with quoted input. For example,

# ./find.sh -i "some quoted string"
grep: quoted: No such file or directory
grep: string: No such file or directory

Note that if $@ doesn't contain the path, the first script does do what I want.


EDIT : Thanks for the great solutions! I went with a combination of the answers:

#!/bin/bash

path="."
end=$#

if [ -d "${!#}" ]
then
    path="${!#}"
    end=$((end - 1))
fi

find "$path" -print0 | xargs -0 grep "${@:1:$end}"
+2  A: 

EDIT:

Original was just slightly off. No removal is to be done if the last argument is not a directory.

#!/bin/bash
if [ -d "${!#}" ]
then
    path="${!#}"
    remove=1
else
    path="."
    remove=0
fi

find "$path" -print0 | xargs -0 grep "${@:1:$(($#-remove))}"
Ignacio Vazquez-Abrams
That is really elegent.
Robert Menteer