Malli Paritala
Malli Paritala

Reputation: 148

Why the second command works and why not first? what is the difference?

I encounter below strange problem in my shell script.

When i execute like below it doesn't work:

excom='/Development/temp_try/testing/\* -o -path /Development/temp_try/testing1/\*'
findcom=$(find /Development/temp_try ! \( -path $excom \) -type f \( ! -name \*.HPSEPFQDN.\* ! -name \*.HPSEPIPCHG.\* \) -exec grep -lF "corp.abc.com" {} \;)

Where as if i execute like below, it works fine:

findcom=$(find /Development/temp_try ! \( -path /Development/temp_try/testing/\* -o -path /Development/temp_try/testing1/\* \) -type f \( ! -name \*.HPSEPFQDN.\* ! -name \*.HPSEPIPCHG.\* \) -exec grep -lF "corp.abc.com" {} \;)

First one output is:

/Development/temp_try/f1
/Development/temp_try/f2
/Development/temp_try/f3
/Development/temp_try/f4
/Development/temp_try/f5
/Development/temp_try/f6
/Development/temp_try/f7
/Development/temp_try/f8
/Development/temp_try/try10
/Development/temp_try/log_test
/Development/temp_try/try10v
/Development/temp_try/try10v1
/Development/temp_try/try10j
/Development/temp_try/try10j1
/Development/temp_try/testing1/f1
/Development/temp_try/testing1/f2
/Development/temp_try/testing1/f3
/Development/temp_try/testing/test1/f1
/Development/temp_try/testing/test1/f2
/Development/temp_try/testing/test1/f3
/Development/temp_try/testing/test1/f4
/Development/temp_try/testing/test1/f5
/Development/temp_try/testing/test1/f6
/Development/temp_try/testing/test1/f7
/Development/temp_try/testing/test1/f8
/Development/temp_try/testing/f1
/Development/temp_try/testing/f2
/Development/temp_try/testing/f3
/Development/temp_try/testing/f4
/Development/temp_try/testing/f5
/Development/temp_try/testing/f6
/Development/temp_try/testing/f7
/Development/temp_try/testing/f8
/Development/temp_try/try10j1_working
/Development/temp_try/try11
/Development/temp_try/try11_original
/Development/temp_try/try8

where as the second one output is:

/Development/temp_try/f1
/Development/temp_try/f2
/Development/temp_try/f3
/Development/temp_try/f4
/Development/temp_try/f5
/Development/temp_try/f6
/Development/temp_try/f7
/Development/temp_try/f8
/Development/temp_try/try10
/Development/temp_try/log_test
/Development/temp_try/try10v
/Development/temp_try/try10v1
/Development/temp_try/try10j
/Development/temp_try/try10j1
/Development/temp_try/try10j1_working
/Development/temp_try/try11
/Development/temp_try/try11_original
/Development/temp_try/try8

Second one perfectly excludes the directories where as first doesn't. I have no clue how they both differ....

Thanks for Answers and comments, Now i understand the issue, could solve the problem.

#!/usr/bin/ksh

filepath="/Development/temp_try"
searchstring="corp.abc.com"

while read exfile
do
lasc=${exfile##${exfile%%?}}
if [ "$lasc" = "/" ]; then
exfile="$exfile*"
fi
if [ "$excom" = "" ]; then
excom="$exfile"
else
#excom="$excom -o -path '$exfile'"
set -A excom "$excom" '-o' '-path' "$exfile"
fi
done <input4


echo "The exclude command is ${excom[@]}"
findcom=$(find $filepath ! \( -path "${excom[@]}" \) -type f \( ! -name \*.HPSEPFQDN.\* ! -name \*.HPSEPIPCHG.\* \) -exec grep -lF $searchstring {} \;)
for filename in $findcom
do
echo $filename
done

My input4 file contains below lines:

/Development/temp_try/testing/
/Development/temp_try/testing1/

Upvotes: 0

Views: 94

Answers (2)

rici
rici

Reputation: 241721

Inside a single-quoted string, \ has no special significance. So the result of

excom='/Development/temp_try/testing/\* -o -path /Development/temp_try/testing1/\*'

is that the value of excom will include two backslash characters.

Backslash characters are not special in filename expansions, so when the value of $excom is filename-expanded and wordsplit (because its expansion is not quoted), the backslash characters continue to be ordinary characters. So the expansion of

find /Development/temp_try ! \( -path $excom \) ...

has the literal words:

find
/Development/temp_try
!
(
-path
/Development/temp_try/testing/\*
-o
-path
/Development/temp_try/testing1/\*

Nothing matches the pattern /Development/temp_try/testing/\* because your filenames do not include backslashes.

Had you left out the backslashes when you defined excom:

excom='/Development/temp_try/testing/* -o -path /Development/temp_try/testing1/*'

then the filename patterns would have been expanded in the invocation of find. In this case, find /Development/temp_try ! \( -path $excom \) ... would expand to:

find
/Development/temp_try
!
(
-path
/Development/temp_try/testing/f1
/Development/temp_try/testing/f2
/Development/temp_try/testing/f3
...

which is also not what you want, since the -path predicate needs to be followed by exactly one pattern, not by a list of filenames.

Consequently, you need to pass the value of excom as a list of quoted words. The only simple way to do that in bash is to use an array, because you can expand an array into a list of quoted array values:

excom=("/Development/temp_try/testing/*"
       -o -path "/Development/temp_try/testing1/*")
findcom=$(find /Development/temp_try ! \( -path "${excom[@]}" \) \
          -type f \( ! -name "*.HPSEPFQDN.*" ! -name "*.HPSEPIPCHG."* \) \
          -exec grep -lF "corp.abc.com" {} \;)

(That definition of findcom, which is not quoted, assumes that no filename produced by the -exec grep command will have whitespace or a pattern metacharacter in its name. In general, that's not a safe assumption.)

Upvotes: 3

anubhava
anubhava

Reputation: 785146

Don't store command line (fully or partially) in simple variables as it creates many issues at the time of variable expansion in shell.

Better to store in shell arrays like this

excom=('/Development/temp_try/testing/*' -o -path '/Development/temp_try/testing1/*')
findcom=$(find /Development/temp_try ! \( -path "${excom[@]}" \) -type f \( ! -name \*.HPSEPFQDN.\* ! -name \*.HPSEPIPCHG.\* \) -exec grep -lF "corp.abc.com" {} \;)

Upvotes: 3

Related Questions