4

I wrote a function in a Bash shell script to search a Linux tree for filenames matching a pattern containing a regular expression, with colour highlighting:

function ggrep {
 LS_="ls --color {}|sed s~./~~"
 [ -n "$1" -a "$1" != "*" ] && NAME_="-iname $1" || NAME_=
 [ -n "$2" ] && EXEC_="egrep -q \"$2\" \"{}\" && $LS_ && egrep -n \"$2\" --color=always \"{}\"|sed s~^B~\ B~" || EXEC_=$LS_
 FIND_="find . -type f $NAME_ -exec sh -c \"$EXEC_\" \\;"
 echo -e \\e[7m $FIND_ \\e[0m
 $FIND_
}

e.g. ggrep a* lists all files starting with a under the current directory tree,

and ggrep a* x lists of files starting with a and containing x

When I run it, I get:

find: missing argument to `-exec'

even though I get the correct output when I copy and paste the line output by "echo" into the terminal. Can anyone please tell me what I've done wrong?

Secondly, it would be great if ggrep * x listed all files containing x, but * expands to a list of filenames and I need to use \* or '*' instead. Is there a way around this? Thanks!

1
  • As a general rule, putting commands as strings into shell variables and running them later is going to cause lots of quoting pain. I would advise finding another way to solve your problem. If you must store commands in variables, use arrays. Commented Jan 13, 2015 at 13:22

2 Answers 2

2

Terminate the find command with \; instead of \\; .

find . -type f $NAME_ -exec sh -c \"$EXEC_\" \;
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, Avinash, but I get the same error. In fact, having from 1 to 4 (inclusive) backslashes gives the same result (same echo output too).
of course. you're doing it within quotes, so there's no need to escape ; at all.
Thanks, too, Karoly. Not having the backslash gives "--color: 1: --color: Syntax error: Unterminated quoted string" for each file in the tree.
Have you tried find . -type f $NAME_ -exec sh -c \"$EXEC_\" {} \;?
So...let's wait for @Gnubie
|
1
eval $FIND_

in the last line of the function body works fine for me.

Expansions in BASH are generally not recursive, so if you load a command from a variable, you should always use "eval" to enforce reprocessing the expanded variable as it was a fresh input. Normally quotes are not handled properly within a string that has already been expanded.

To your second problem, I think there is no satisfactory solution. The shell will always expand * before passing it to anything controlled by you. You can disable this expansion, but that is a global setting. Anyway, I think that this expansion could actually act in favor of your function. Consider rewriting it in a way that takes advantage of it. (I did not analyze whether the current version was close to that or not.)

1 Comment

Well done, Tomasz: eval solves the problem! Thanks too for explaining the * expansion. Guess I've to use a different symbol to save some typing...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.