LinuxQuestions.org
LinuxAnswers - the LQ Linux tutorial section.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 03-02-2010, 02:18 AM   #1
escalf
LQ Newbie
 
Registered: Mar 2010
Posts: 2

Rep: Reputation: 0
Question find: paths must precede expression -- already checked google/man/faqs


Running into a little bit of an issue with find in my script...
When running the find via script, I get
find: paths must precede expression
Usage: find [-H] [-L] [-P] [path...] [expression]

However, when running from cli, it runs without issue.
My first thought - along with everything else I've seen on this issue across google, and linuxquestions - was escapism. No such luck. All wildcards as in 'style' quotes, and I've tried using \* style escaped wildcards to no avail.

I have things set up a little weird, so that may be the issue. Since this script is one that will ultimately be maintained and edited by a number of people, I've set it up so the primary search strings can be easily changed by simply adding to an array, The script then concatenates everything down into one large variable that contains the singular search string for the find command. I'll show the code for all of that, below...

First, the beginning of everything...
Code:
declare -rx CHECK_LIST_FIRST='*.mp3'
declare -a CHECK_LIST
declare -rx CHECK_LIST=(
        '*.divx'
        '*crack*'
        '*keygen*'
        '*serial*'
        '*.torrent'
        '*.xvid'
        '*.dvdr*'
        '*dtv'
        '*.720p'
        '*.1080*'
        '*.rar'
)
declare -x SEARCHTERMS
We go through a little sanity checking and misc whatnot, and then concatenate the array down to a single var:
Code:
TERMCOUNTER=1
        declare -a TERMSARRAY
        for CHECKTERM in `echo ${CHECK_LIST[*]}`
        do
        TERMSARRAY[${TERMCOUNTER}]="-or -iname '${CHECKTERM}' -printf '%u \n'"
        let "TERMCOUNTER = $TERMCOUNTER + 1"
        done
        SEARCHTERMS2=`echo ${TERMSARRAY[*]}`
        SEARCHTERMS="-iname '${CHECK_LIST_FIRST}' -printf '%u \n' ${SEARCHTERMS2}"
Then we get on with our search:
Code:
ionice -n4 -c 2 find /home -path /home/virtfs -prune -o -type f ${SEARCHTERMS} >> /root/results.find
Here's some debugging output...
From when the array is being created, this is $SEARCHTERMS once it's complete:
Code:
-iname '*.mp3' -printf '%u \n' -or -iname '*.divx' -printf '%u \n' -or -iname '*crack*' -printf '%u \n' -or -iname '*keygen*' -printf '%u \n' -or -iname '*serial*' -printf '%u \n' -or -iname '*.torrent' -printf '%u \n' -or -iname '*.xvid' -printf '%u \n' -or -iname '*.dvdr*' -printf '%u \n' -or -iname '*dtv' -printf '%u \n' -or -iname '*.720p' -printf '%u \n' -or -iname '*.1080*' -printf '%u \n' -or -iname '*.rar' -printf '%u \n'
and here's the find command echo'ed:
Code:
ionice -n4 -c 2 find /home -path /home/virtfs -prune -o -type f -iname '*.mp3' -printf '%u \n' -or -iname '*.divx' -printf '%u \n' -or -iname '*crack*' -printf '%u \n' -or -iname '*keygen*' -printf '%u \n' -or -iname '*serial*' -printf '%u \n' -or -iname '*.torrent' -printf '%u \n' -or -iname '*.xvid' -printf '%u \n' -or -iname '*.dvdr*' -printf '%u \n' -or -iname '*dtv' -printf '%u \n' -or -iname '*.720p' -printf '%u \n' -or -iname '*.1080*' -printf '%u \n' -or -iname '*.rar' -printf '%u \n' >> /root/results.find
Ergo, we should be in a disco ballroom somewhere, getting down. Instead, I get:
find: paths must precede expression
Usage: find [-H] [-L] [-P] [path...] [expression]

...what, praytheetell, am I missing?

(Muchas Danke Comrades)

-A very flustered, and fairly annoyed at everything bash and find,
--Eric

Last edited by escalf; 03-02-2010 at 02:19 AM. Reason: changing to instant email notification
 
Old 03-02-2010, 02:48 AM   #2
gnashley
Amigo developer
 
Registered: Dec 2003
Location: Germany
Distribution: Slackware
Posts: 4,752

Rep: Reputation: 462Reputation: 462Reputation: 462Reputation: 462Reputation: 462
For starters, I think you need to use double-quotes around wildcards:
"*.divx" -printf '%u \n' -or -iname "*crack*"
 
Old 03-02-2010, 03:19 AM   #3
escalf
LQ Newbie
 
Registered: Mar 2010
Posts: 2

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by gnashley View Post
For starters, I think you need to use double-quotes around wildcards:
"*.divx" -printf '%u \n' -or -iname "*crack*"
I started out that way (using double quotes). A lot of threads I found said that due to the way things are eval'd in script, you needed to use single quotes. So, I tried single. Haven't reverted yet.
Works fine either way at cli.
 
Old 03-02-2010, 06:01 AM   #4
colucix
Moderator
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,488

Rep: Reputation: 1956Reputation: 1956Reputation: 1956Reputation: 1956Reputation: 1956Reputation: 1956Reputation: 1956Reputation: 1956Reputation: 1956Reputation: 1956Reputation: 1956
Maybe putting an eval in front of the ionice command solves the problem. However I'd do something slightly different:

1) to apply multiple logical OR to the action alternative to -prune, better to embed them within parentheses, e.g.
Code:
find /path/to/search -wholename /path/to/exclude -prune -o \( multiple expressions here \) -print
otherwise the command is garbled. Moreover, in this way you can avoid to put multiple -printf actions.

2) when the shell applies variable expansion, in most cases the resulting "expanded" string is left untouched. This means that you don't really need so many single quotes and/or escape characters, otherwise the shell is garbled now. I'd remove the single quotes from the value of the variable SEARCHTERMS, so that the resulting code could be something like this (the declaration part being the same)
Code:
TERMCOUNTER=1
declare -a TERMSARRAY
for CHECKTERM in `echo ${CHECK_LIST[*]}`
do
  TERMSARRAY[${TERMCOUNTER}]="-o -iname ${CHECKTERM}"
  let "TERMCOUNTER = $TERMCOUNTER + 1"
done
SEARCHTERMS2=`echo ${TERMSARRAY[*]}`
SEARCHTERMS="( -iname ${CHECK_LIST_FIRST} ${SEARCHTERMS2} )"

ionice -n4 -c2 find /home -wholename /home/virtfs -prune -o -type f ${SEARCHTERMS} -printf "%u\n"
Last note: be sure you don't put the script in a directory that contains also some files that match any of the search patterns. If this is the case, the pattern (*.rar for example) will be expanded to that name inside the for loop. The resulting find command will have something like "-iname somefile.rar" instead of "-iname *.rar" and it will miss some results.

Last edited by colucix; 03-02-2010 at 06:02 AM.
 
Old 03-02-2010, 10:02 AM   #5
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,533
Blog Entries: 28

Rep: Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176
Quote:
Originally Posted by escalf View Post
I started out that way (using double quotes). A lot of threads I found said that due to the way things are eval'd in script, you needed to use single quotes. So, I tried single. Haven't reverted yet.
Works fine either way at cli.
Single quotes are functionally identical to double quotes as long as the quoted string does not contain:
  • $, `, \, and, when history expansion is enabled, !. Full details here.
  • any single quotes
Using either single or double quotes avoids the problem colucix mentioned of "the pattern (*.rar for example) will be expanded to that name inside the for loop".

Using ionice results in the find command strings being expanded twice in which case you need to quote within quotes to generate the desired command string, for example
Code:
ionice -n4 -c 2 find /home -path /home/virtfs -prune -o -type f "'${SEARCHTERMS}'" >> /root/results.find
The double quotes allow ${SEARCHTERMS} to be expanded during the first expansion; the single quotes ensure that the expansion of ${SEARCHTERMS} remains as a single word (and not subject to filename expansion) during the second expansion.

Incidentally the {} in ${SEARCHTERMS} is not necessary; $SEARCHTERMS would be sufficient.
 
Old 03-02-2010, 10:12 AM   #6
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,478

Rep: Reputation: 1888Reputation: 1888Reputation: 1888Reputation: 1888Reputation: 1888Reputation: 1888Reputation: 1888Reputation: 1888Reputation: 1888Reputation: 1888Reputation: 1888
I am curious, as not being a find guru or anything, but as you have already gone to the trouble of iterating
through your array of search items, why not just do the find in the loop?

Please don't bash me for asking, but I was just wondering if this is better than the overhead of what I have
mentioned?

Enquiring mind
 
  


Reply

Tags
find


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
find: paths must precede expression lead2gold Linux - General 11 02-27-2014 07:06 AM
Problem with find: paths must precede expression troelskn Programming 11 07-29-2009 02:48 AM
Algorithm to find paths xeon123 Programming 5 04-24-2007 02:18 AM
waht file have paths for man? man.conf? where? xcore_on Linux - Newbie 4 05-23-2006 09:38 AM
Wine, Games, and Slack 10 - already checked google and linuxquestions Aeoruuk Linux - Newbie 1 12-29-2004 10:27 AM


All times are GMT -5. The time now is 12:37 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration