tags:

views:

432

answers:

5

I'm new to bash scripts (and the *nix shell altogether) but I'm trying to write this script to make grepping a codebase easier.

I have written this

#!/bin/bash
args=("$@");
for arg in args
 grep arg * */* */*/* */*/*/* */*/*/*/*;
done

when I try to run it, this is what happens:

~/Work/richmond $ ./f.sh "\$_REQUEST\['a'\]"
./f.sh: line 4: syntax error near unexpected token `grep'
./f.sh: line 4: `       grep arg * */* */*/* */*/*/* */*/*/*/*;'
~/Work/richmond $

How do I do this properly?

And, I think a more important question is, how can I make grep recurse through subdirectories properly like this?

Any other tips and/or pitfalls with shell scripting and using bash in general would also be appreciated.

+3  A: 

On recusive grepping:

Depending on your grep version, you can pass -R to your grep command to have it search Recursively (in subdirectories).

Rob
+7  A: 

The syntax error is because you're missing do. As for searching recursively if your grep has the -R option you would do:

#!/bin/bash
for arg in "$@"; do
   grep -R "$arg" *
done

Otherwise you could use find:

#!/bin/bash
for arg in "$@"; do
   find . -exec grep "$arg" {} +
done

In the latter example, find will execute grep and replace the {} braces with the file names it finds, starting in the current directory ..

(Notice that I also changed arg to "$arg". You need the dollar sign to get the variable's value, and the quotes tell the shell to treat its value as one big word, even if $arg contains spaces or newlines.)

John Kugelman
this is perfect, thank you
Carson Myers
When iterating over command line arguments, you can also omit the "$@" and write it as just "for arg; do ..."
Idelic
+1  A: 

The best solution is stated above, but try putting your statement in back ticks:

`grep ...`
Topher Fangio
There is no reason to use backticks (or the preferred `$()`) in the OP's script or in any version posted in answers so far. If he was assigning the result to a variable or using it in-line as an argument to another command, that would be different.
Dennis Williamson
+1  A: 

You should use 'find' plus 'xargs' to do the file searching.

for arg in "$@"
do
    find . -type f -print0 | xargs -0 grep "$arg" /dev/null
done

The '-print0' and '-0' options assume you're using GNU grep and ensure that the script works even if there are spaces or other unexpected characters in your path names. Using xargs like this is more efficient than having find execute it for each file; the /dev/null appears in the argument list so grep always reports the name of the file containing the match.

You might decide to simplify life - perhaps - by combining all the searches into one using either egrep or grep -E. An optimization would be to capture the output from find once and then feed that to xargs on each iteration.

Jonathan Leffler
A: 

Have a look at the findrepo script which may give you some pointers

pixelbeat