LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (http://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Escaping the parentheses characters in a bash script which calls find with -prune (http://www.linuxquestions.org/questions/linux-newbie-8/escaping-the-parentheses-characters-in-a-bash-script-which-calls-find-with-prune-818406/)

paul.richter 07-06-2010 11:34 PM

Escaping the parentheses characters in a bash script which calls find with -prune
 
I have a bash script which calls the 'find' command with multiple directories to prune.

Here is the entire script:

Code:

#!/bin/bash

SRCDIR="$HOME/test"
PRED="-wholename '$SRCDIR/skip1' -o -wholename '$SRCDIR/skip2'"

echo find $SRCDIR '\(' $PRED '\)' -prune -or -print
find $SRCDIR '(' $PRED ')' -prune -or -print

I have under SRCDIR the directories skip1, skip2, look1, and look2, each with a few files in it.

If I run the script and paste the echoed line into the bash prompt, it will print out:
Code:

/home/paul/test
/home/paul/test/skip1
/home/paul/test/look2
/home/paul/test/look2/file2.txt
/home/paul/test/look2/file1.txt
/home/paul/test/skip2
/home/paul/test/look1
/home/paul/test/look1/file2.txt
/home/paul/test/look1/file1.txt

I understand that the parentheses \( and \) need to be escaped to protect them from the shell, and this is the result I want.

I want the next line in the script to do the exact same thing, but called from the script. But the result is :
Code:

/home/paul/test
/home/paul/test/skip1
/home/paul/test/skip1/file2.txt
/home/paul/test/skip1/file1.txt
/home/paul/test/look2
/home/paul/test/look2/file2.txt
/home/paul/test/look2/file1.txt
/home/paul/test/skip2
/home/paul/test/skip2/file2.txt
/home/paul/test/skip2/file1.txt
/home/paul/test/look1
/home/paul/test/look1/file2.txt
/home/paul/test/look1/file1.txt

I can not figure out how to properly escape the parentheses characters within the script. I've tried all sorts of variations instead of '(' and ')', and here are the results:
( ... ) -> bash error: syntax error near unexpected token `('
'\(' ... '\)' -> find error: paths must precede expression
"\(" ... "\)" -> find error: paths must precede expression
\( ... \) -> same as '(' ... ')' , find prints out all directories

How can I properly tell find to treat the parentheses as precedence operators?

paul.richter 07-06-2010 11:40 PM

I found the following workaround:

bash -c "find $SRCDIR \( $PRED \) -prune -or -print"

But this is just a horrible ugly hack, calling bash from within the script.

konsolebox 07-06-2010 11:50 PM

try to cast eval for that:
Code:

eval "find $SRCDIR \( $PRED \) -prune -or -print"
edit: i think it's safer to use arrays:
Code:

#!/bin/bash

SRCDIR=$HOME/test
PRED=(-wholename "$SRCDIR/skip1" -o -wholename "$SRCDIR/skip2")

echo find "$SRCDIR" \( "${PRED[@]}" \) -prune -or -print
find "$SRCDIR" \( "${PRED[@]}" \) -prune -or -print


grail 07-07-2010 12:42 AM

Is it just me or does the first post have the brackets NOT escaped??
Quote:

find $SRCDIR '(' $PRED ')' -prune -or -print
Now I am not saying it will definately work but you are comparing apples and oranges I believe.

Andrew Benton 07-07-2010 07:47 AM

I can't test this 'cos I don't have the files to search, but I had a problem using find with ssh (I was tying to use find within a script to search for files on another computer). My solution was to escape the backslash with two more backslashes like this
Code:

file_list=($(ssh eccles find ~/save/sources \\\( -path ~/save/sources/.git -o -path \
  ~/save/sources/aspell6-en \\\) -prune -o -type f))


grail 07-07-2010 08:20 AM

This works:
Code:

#!/bin/bash

SRCDIR="$HOME/test"
PRED="-wholename $SRCDIR/skip1 -o -wholename $SRCDIR/skip2"

echo "find $SRCDIR \( $PRED \) -prune -or -print"
find $SRCDIR \( $PRED \) -prune -or -print

As usual we were getting too carried away with how to make it look right when exactly as you do it on the command line works just fine :)

paul.richter 07-07-2010 09:10 PM

Thanks, grail.

I see the difference is the removed single-quoting of $SRCDIR/skip1. If it is quoted it will look in the skip directories. For my purposes not having the quotes will work, but I'm afraid if will fail on a directory with a space in its name. I guess that's a separate question though...I will work on it.

grail 07-07-2010 09:19 PM

You could try putting in escaped quotes (\") around the path to be excluded to help preserve the spaces.

paul.richter 07-07-2010 09:32 PM

Quote:

Originally Posted by grail (Post 4026856)
You could try putting in escaped quotes (\") around the path to be excluded to help preserve the spaces.

Nope, unescaped single quotes, escaped single quotes, escaped double quotes all cause find to look in the skip directories.

grail 07-07-2010 09:59 PM

Where there is a will there is a way :)
Code:

#!/bin/bash

SRCDIR="$HOME/test"
PRED="-wholename \"$SRCDIR/skip[12]\""

echo "find $SRCDIR \( $PRED \) -prune -or -print"
eval find $SRCDIR $PRED -prune -or -print

If you still need to have individual names you need to go nuts on the escaping:
Code:

eval find $SRCDIR \\\( $PRED \\\) -prune -or -print
Edit: hold the phone ... for the last example you can place your brackets in the variable:
Code:

PRED="\( -wholename \"$SRCDIR/skip1\" -o -wholename \"$SRCDIR/skip2\" \)"


All times are GMT -5. The time now is 04:57 PM.