Chun Yip Wong wrote: > I prefer using find with script in this way: find $dir $pattern.where > pattern=" -name *.sh ! -name *.txt ... etc."
There is a problem with insufficiently quoted shell file glob meta characters in that pattern. That's a problem unrelated to find. > The built findutils version is 4.7. it fails to work with such message > > find: paths must precede expression: 'test.sh' > find: possible unquoted pattern after predicate '-name' And there is a warning about "possible unquoted pattern" but since we can see the pattern we know that yes the pattern is not quoted and that is an error of the command line. > I know when there are multiple files, such as a.txt b.txt c.txt, find . > -name *.txt will cause such messages and solve with quoted the '*.txt' > It is more convenient to define a pattern and no need to quote all > extensions one by one, line by line using scripts. The "*" file glob character is a shell meta-character. The shell being your command line shell. One of bash, ksh, zsh, or possibly even tcsh, csh, or possibly another. The shell is not find. The shell reads the command and expands shell file glob patterns like "*.txt" into files that match. After the shell has expanded these characters then the resulting multiple arguments are passed to the command. In this case the command find. In order to observe this expansion the "echo" command is most easily used. If one uses echo they can see how the patterns are expanded. Or if there is no match then how it is not expanded. It is a data dependent expansion based upon whether any files exist that match the pattern or not. Which is why any characters that happen to be shell metacharacters must be quoted to prevent this expansion. For use in the fine -name option it is not desired to have them expanded and therefore this must be prevented. $ touch a.txt b.txt c.txt $ pattern=" -name *.sh ! -name *.txt" $ echo find $dir $pattern find -name *.sh ! -name a.txt b.txt c.txt And here we see that -name *.txt is expanded to be -name a.txt b.txt c.txt when -name uses exactly one argument. The "-name a.txt" is read and then b.txt and c.txt is extra and not part of -name. The expansion of the shell is useful for other commands that are not find to use. For example they are useful with ls. $ echo ls -log *.txt ls -log a.txt b.txt c.txt $ ls -log *.txt -rw-rw-r-- 1 0 Feb 7 20:36 a.txt -rw-rw-r-- 1 0 Feb 7 20:36 b.txt -rw-rw-r-- 1 0 Feb 7 20:36 c.txt That is useful for ls and other commands but it is not useful for find and therefore those file glob characters, and other shell meta characters, must be quoted to prevent this expension. > I prefer using find with script in this way: find $dir $pattern.where > pattern=" -name *.sh ! -name *.txt ... etc." Quote the arguments. Since this is in a double quoted string then it is convenient to use single quotes in the string. pattern=" -name '*.sh' ! -name '*.txt' ... etc." And then the result will be this. First a reminder of the problem case. $ pattern=" -name *.sh ! -name *.txt"; echo find $dir $pattern find -name *.sh ! -name a.txt b.txt c.txt And then we fix it by adding quotes. $ pattern=" -name '*.sh' ! -name '*.txt'"; echo find $dir $pattern find -name '*.sh' ! -name '*.txt' As some background information the "*" is called a file glob character and the expansion is called globbing (see "man glob") because the "*" matches a "glob" of file name characters. A glob being a bunch of characters. It's a very casual word idiom for a bunch of characters. This dates back to the earliest implementation of Unix. Bob