shsvr:/home/tom/tmp/test1$ echo $SHELL
/bin/bash
shsvr:/home/tom/tmp/test1$ shopt -s extglob
shsvr:/home/tom/tmp/test1$ ls *
-rw-r--r-- 1 tom msc 0 Feb 1 15:47 File1.java
-rw-r--r-- 1 tom msc 0 Feb 1 15:47 File2.java
-rw-r--r-- 1 tom msc 0 Feb 1 15:47 Makefile
SCCS:
total 0
-rw-r--r-- 1 tom msc 0 Feb 1 15:47 s.File1.java
-rw-r--r-- 1 tom msc 0 Feb 1 15:47 s.Makefile
-rw-r--r-- 1 tom msc 0 Feb 1 15:47 s.File2.java
shsvr:/home/tom/tmp/test1$ find . -name !(s.*.java)
find: paths must precede expression
Usage: find [path...] [expression]
shsvr:/home/tom/tmp/test1$ find SCCS -name !(s.*.java)
find: paths must precede expression
Usage: find [path...] [expression]
shsvr:/home/tom/tmp/test1$ cd SCCS
shsvr:/home/tom/tmp/test1/SCCS$ find . -name !(s.*.java)
./s.Makefile
What should I do to make find works properly ?
Thanks in advance.
>
> shsvr:/home/tom/tmp/test1$ find . -name !(s.*.java)
> find: paths must precede expression
> Usage: find [path...] [expression]
>
The argument following -name is usually quoted so the shell won't expand
it. Find is an external command, so its globbing isn't affected by bash
shopt options, but you can use:
find . ! -name 's.*.java'
Note that strictly speaking, find is not doing globbing, that is
it doesn't expand the wildcard pattern into a list of files as
the shell does. Instead it uses the pattern on the basename of
every file it is walking through to decide whether it matches or
not (and going on or not with the other predicates). So it is
doing "matching" only.
In shells, wildcard patterns can be used both for globbing
(filename generation) as in
echo *.txt
which it expands into echo x.txt y.txt...
or for matching as in
case $text in
($pattern) ...
esac
or ${var#$pattern}...
--
Stephane
Thanks. I know now. I just want a more powerful find utility so that I
can find files using very complicated criteria(regular expressions).
Are there any kinds of tool available ? I am puzzled that why there
is no an enhanced find utility. Its filename matching is too weak.
GNU and FreeBSD find have the -iregex and -regex predicate which
should be enough for any need.
But in any case, you can run any utility to do the matching with
the -exec predicate.
find . -exec awk 'BEGIN{exit(!(ARGV[1] ~ /pattern/))}' {} \; -print
for instance.
--
Stephane
or of course:
find . -exec bash -c '
shopt -s extglob
case $1 in
(pattern) exit 0;;
(*) exit 1;;
esac' inline {} \; -print
(of course that won't be as fast as using find's own matching
operators)
Note that the zsh shell has the ability to replace find with its
recursive globbing:
print -rl -- **/complex-pattern
for instance.
--
Stephane
This expanded to find . -name File1.java File2.java Makefile SCCS
-name doesn't support extended globbing and the patterns should be quoted
to avoid unintended expansion by the shell. What you really want is:
find . ! -name 's.*.java'
Dan Mercer
: find: paths must precede expression
shsvr:/home/tom/tmp$ find '!(test1|test2)' -type f
find: invalid predicate `!(test1|test2)'
shsvr:/home/tom/tmp$ find !(test1|test2) -type f
file1
t
test3/A.java
shsvr:/home/tom/tmp$ find (test1|test2) -type f
bash: syntax error near unexpected token `|'
shsvr:/home/tom/tmp$ find '(test1|test2)' -type f
find: invalid predicate `(test1|test2)'
shsvr:/home/tom/tmp$ find test1|test2 -type f
bash: test2: command not found
shsvr:/home/tom/tmp$ find 'test1|test2' -type f
find: test1|test2: No such file or directory
shsvr:/home/tom/tmp$ find test[1-3] -type f
test1/SCCS/s.File1.java
test1/SCCS/s.Makefile
test1/SCCS/s.File2.java
test1/File1.java
test1/File2.java
test1/Makefile
test2/SCCS/s.File1.java
test2/SCCS/s.Makefile
test2/SCCS/s.File2.java
test2/File1.java
test2/File2.java
test2/Makefile
test3/A.java
shopt only affects the shell. As someone else replied earlier, with GNU
or BSD find you can use -regex instead of -name. Otherwise you can pipe
the output of find to grep or other programs.
> Please see the following examples where some succeed while others
> fail:
> shsvr:/home/tom/tmp$ ls
> total 20
> -rwsrwxrwx 1 tom msc 9 Jan 19 18:08 file1*
> -rwxrwxrwx 1 tom msc 66 Jan 23 19:59 t*
> drwxr-xr-x 3 tom msc 4096 Feb 1 15:47 test1/
> drwxr-xr-x 3 tom msc 4096 Feb 1 20:16 test2/
> drwxr-xr-x 2 tom msc 4096 Feb 2 08:56 test3/
> shsvr:/home/tom/tmp$ ls test3/
> total 0
> -rw-r--r-- 1 tom msc 0 Feb 2 08:56 A.java
>
> shsvr:/home/tom/tmp$ find '!(test1|test2)' -type f
> find: invalid predicate `!(test1|test2)'
>
You can exclude directories with -prune.
find . -name 'test[12]' -prune -o -type f