I need a pointer for command line tools to find files. 'locate' and 'whereis' work OK for most things as long as they are in that database, but I need to pattern/filename match the way 'find' does things... but across multiple directories. As far as I can tell from reading the man page on 'find' I can only search the current directory, or a directory I specify when I type in the command. So, I want to search across multiple directories the way 'locate' does, but I don't want to use the database thing that 'locate' uses... I want to pattern match. Can 'find' do this? Is there a better way to do this from the console? C.
On Sun, 24 Mar 2002 10:30:56 +0100 Clayton Cornell <c.cornell@chello.nl> wrote:
So, I want to search across multiple directories the way 'locate' does, but I don't want to use the database thing that 'locate' uses... I want to pattern match. Can 'find' do this? Is there a better way to do this from the console?
#find files recursively and find foo in them find . -type f -exec grep foo {} \; i#s one way to do it with find. #Some people prefer to use xargs (look at man xargs. find . -type f | grep -v searchstring | xargs egrep; I prefer perl because it allows you more control over customization of the script. Heres one I use: zgrep ############################################################ #!/usr/bin/perl # Recursively searchs down thru directories for pattern in files. # returns directory and line numbers too, and only searches text files. # usage zgrep 'search pattern' 'ext'(optional with no .) use warnings; use strict; use File::Find; my ($search, $ext) = @ARGV; if (defined $ext) {$ext = ".$ext"} else {$ext = '.*'}; die "Usage : greprz 'search' 'extension' (extension optional)\n" if ($search eq ""); @ARGV = (); find (sub { push @ARGV, $File::Find::name if (-f and -T and $ext or /\Q$ext$/)}, "."); while (<ARGV>) { close ARGV if eof; print "$ARGV: $. :$_\n" if /$search/; } ############################################################# $|=1;while(1){print pack("h*",'75861647f302d4560275f6272797f3');sleep(1); for(1..16){for(8,32,8,7){print chr($_);}select(undef,undef,undef,.05);}}
On Sunday 24 March 2002 13:45, zentara wrote:
On Sun, 24 Mar 2002 10:30:56 +0100
Clayton Cornell <c.cornell@chello.nl> wrote:
So, I want to search across multiple directories the way 'locate' does, but I don't want to use the database thing that 'locate' uses... I want to pattern match. Can 'find' do this? Is there a better way to do this from the console?
#find files recursively and find foo in them find . -type f -exec grep foo {} \;
OK, this (and the perl script) allows me to look into each file and find each instance of foo in each file. Assume I want to search for filenames... for example all jpegs in a directory tree. Something along the lines of find *.jpg in /home/user/mydirectory and all subdirs of mydirectory and have it only return the filenames... something like what dir *.jpg /s would do in DOS. Thanks for the perl script BTW... I am starting to teach myself perl, and this will go into my collection. C.
i#s one way to do it with find.
#Some people prefer to use xargs (look at man xargs. find . -type f | grep -v searchstring | xargs egrep;
I prefer perl because it allows you more control over customization of the script. Heres one I use: zgrep ############################################################ #!/usr/bin/perl # Recursively searchs down thru directories for pattern in files. # returns directory and line numbers too, and only searches text files. # usage zgrep 'search pattern' 'ext'(optional with no .) use warnings; use strict; use File::Find; my ($search, $ext) = @ARGV; if (defined $ext) {$ext = ".$ext"} else {$ext = '.*'}; die "Usage : greprz 'search' 'extension' (extension optional)\n" if ($search eq ""); @ARGV = (); find (sub { push @ARGV, $File::Find::name if (-f and -T and $ext or /\Q$ext$/)}, "."); while (<ARGV>) { close ARGV if eof; print "$ARGV: $. :$_\n" if /$search/; } #############################################################
On Sun, 24 Mar 2002 14:33:30 +0100 Clayton Cornell <c.cornell@chello.nl> wrote:
On Sunday 24 March 2002 13:45, zentara wrote:
On Sun, 24 Mar 2002 10:30:56 +0100
Clayton Cornell <c.cornell@chello.nl> wrote:
So, I want to search across multiple directories the way 'locate' does, but I don't want to use the database thing that 'locate' uses... I want to pattern match. Can 'find' do this? Is there a better way to do this from the console?
#find files recursively and find foo in them find . -type f -exec grep foo {} \;
OK, this (and the perl script) allows me to look into each file and find each instance of foo in each file. Assume I want to search for filenames... for example all jpegs in a directory tree. Something along the lines of
find *.jpg in /home/user/mydirectory and all subdirs of mydirectory
and have it only return the filenames... something like what dir *.jpg /s would do in DOS.
Ok, that is just a simple use of find find . -name "*.jpg" ;;
Thanks for the perl script BTW... I am starting to teach myself perl, and this will go into my collection.
Yeah, perl is they way to go. Here is another one that finds and then deletes files according to a pattern. You can easily modify it to just find, and not delete. zdel ################################################### #!/usr/bin/perl # Recursively searchs down thru directories for files, with or without ext. # unlinks (deletes) files matching the patterns on commandline # prompts for confirmation before deleting # usage zdel 'pattern'; example '1022', '.bak', '.html.bak' use warnings; use strict; use File::Find; my (@patterns) = @ARGV; if (!defined $ARGV[0]) {print 'Usage: zdel pattern1 pattern2 pattern3 ....',"\n"}; @ARGV = (); find (\&found,"."); $" = "\n"; print "@ARGV\n"; print 'Files selected are listed above. Delete? y/(n) '; if (<STDIN> =~ /^[yY]/){&del} else {exit} print "$#ARGV files deleted\n"; exit; sub found{foreach my $pattern(@patterns){ push @ARGV, $File::Find::name if (($_ =~ /$pattern/) and -f)} } sub del{foreach (@ARGV) { unlink($_) or die "Can't delete $_: $!\n"} } ######################################################### -- $|=1;while(1){print pack("h*",'75861647f302d4560275f6272797f3');sleep(1); for(1..16){for(8,32,8,7){print chr($_);}select(undef,undef,undef,.05);}}
On Sun, 24 Mar 2002 09:17:24 -0500, you wrote:
Ok, that is just a simple use of find find . -name "*.jpg" ;;
Nope, that won't keep the shell from expanding the wildcard. Either use single quotes or a backslash to inhibit wildcard expansion: find <directory_to_start_searching> -name \*.jpg find <directory_to_start_searching> -name '*.jpg' Philipp
On Sun, 24 Mar 2002, Philipp Thomas wrote: pt> On Sun, 24 Mar 2002 09:17:24 -0500, you wrote: pt> pt> >Ok, that is just a simple use of find pt> >find . -name "*.jpg" ;; pt> pt> Nope, that won't keep the shell from expanding the wildcard. Either use single pt> quotes or a backslash to inhibit wildcard expansion: pt> pt> find <directory_to_start_searching> -name \*.jpg pt> find <directory_to_start_searching> -name '*.jpg' pt> If you like bash routines, here's one I did a while ago that I stuck in my .alias file, it's a little overkill, but I find it useful. function fww { case "$1" in -f|--file) CONTENTS=${2} SCANDIR=${3-./}/ find ${SCANDIR} -follow -name "*${CONTENTS}*" -exec ls --color=auto {} \; ;; -h|--help) echo "Usage: fww [OPTION] PATTERN [PATH]" echo "Search for PATTERN in/within PATH." echo "Example: fww "hello.*world" /usr/local" echo "" echo " -f, --file locate PATTERN within the name of file(s)" echo " -h, --help summary of the command-line usage" echo "" echo " <PATTERN> search for files that contain PATTERN within" echo " it's body, multiple words can be supplied" echo " when they are enclosed within quotes." echo " <PATH> any filename/path or parts of a filename/path" echo " can be supplied, rules for PATTERN apply." echo "" echo "With no PATH supplied, default will be to current directory." echo "" ;; *) if [ -n "$1" ]; then CONTENTS=${1} SCANDIR=${2-.}/ find ${SCANDIR} -follow -type f -exec grep -ln --regexp="${CONTENTS}" {} \; else echo "Usage: fww [OPTION] PATTERN [PATH]" echo "Search for PATTERN in/within PATH." echo "Try \`fww --help' for more information." fi ;; esac } pt> Philipp pt> pt> -- S.Toms - smotrs at mindspring.com - www.mindspring.com/~smotrs SuSE Linux v7.3+ - Kernel 2.4.10-4GB
On Sun, 24 Mar 2002 21:39:38 +0100 Philipp Thomas <pthomas@suse.de> wrote:
On Sun, 24 Mar 2002 09:17:24 -0500, you wrote:
Ok, that is just a simple use of find find . -name "*.jpg" ;;
Nope, that won't keep the shell from expanding the wildcard. Either use single quotes or a backslash to inhibit wildcard expansion:
find <directory_to_start_searching> -name \*.jpg find <directory_to_start_searching> -name '*.jpg'
Hmmm, find . -name "*.jpg" works for me with output identical to \*.jpg or '*.jpg' . Wonder why? I'm using bash from suse7.2. -- $|=1;while(1){print pack("h*",'75861647f302d4560275f6272797f3');sleep(1); for(1..16){for(8,32,8,7){print chr($_);}select(undef,undef,undef,.05);}}
On Monday 25 March 2002 13:39, zentara wrote:
On Sun, 24 Mar 2002 21:39:38 +0100
Philipp Thomas <pthomas@suse.de> wrote:
On Sun, 24 Mar 2002 09:17:24 -0500, you wrote:
Ok, that is just a simple use of find find . -name "*.jpg" ;;
Nope, that won't keep the shell from expanding the wildcard. Either use single quotes or a backslash to inhibit wildcard expansion:
find <directory_to_start_searching> -name \*.jpg find <directory_to_start_searching> -name '*.jpg'
Hmmm, find . -name "*.jpg" works for me with output identical to \*.jpg or '*.jpg' . Wonder why? I'm using bash from suse7.2.
It's standard shell behaviour. Expansion of the wildcards is done by the shell before it tries to execute the command. If you have a file in the current directory ending in jpg then the shell finds it and expands it on the command line. If there is no file that the shell can expand to the entire expression is passed to find. You can test this with the exact same command, but first create a jpg file in the current directory (touch trash.jpg). Then you will only find that one file (or any other file with the exact same name.) Regards, jimmo -- --------------------------------------- "Be more concerned with your character than with your reputation. Your character is what you really are while your reputation is merely what others thing you are." -- John Wooden --------------------------------------- Be sure to visit the Linux Tutorial: http://www.linux-tutorial.info --------------------------------------- NOTE: All messages sent to me in response to my posts to newsgroups or forums are subject to reposting.
On Mon, 25 Mar 2002 19:24:55 +0100 James Mohr <suse_mailing_list@jimmo.com> wrote:
On Monday 25 March 2002 13:39, zentara wrote:
On Sun, 24 Mar 2002 21:39:38 +0100
Philipp Thomas <pthomas@suse.de> wrote:
On Sun, 24 Mar 2002 09:17:24 -0500, you wrote:
Ok, that is just a simple use of find find . -name "*.jpg" ;;
Nope, that won't keep the shell from expanding the wildcard. Either use single quotes or a backslash to inhibit wildcard expansion:
find <directory_to_start_searching> -name \*.jpg find <directory_to_start_searching> -name '*.jpg'
Hmmm, find . -name "*.jpg" works for me with output identical to \*.jpg or '*.jpg' . Wonder why? I'm using bash from suse7.2.
It's standard shell behaviour. Expansion of the wildcards is done by the shell before it tries to execute the command. If you have a file in the current directory ending in jpg then the shell finds it and expands it on the command line. If there is no file that the shell can expand to the entire expression is passed to find. You can test this with the exact same command, but first create a jpg file in the current directory (touch trash.jpg). Then you will only find that one file (or any other file with the exact same name.)
Yeah, I understand shell behavior with *. The original posts dealt with whether using "" quotes would work. They do on my system, for example, the following give identical output, whether I use "" , '' , or \ zentara@zentara:~/1 > ls dobears.jpg flag.jpg frontpage.bmp hula.gif linus.jpg linus1.jpg mscement.png oldglory.ps trash.jpg tuxvolt_a.gif zentara@zentara:~/1 > find . -name "*.jpg" ./trash.jpg ./linus1.jpg ./flag.jpg ./linus.jpg ./dobears.jpg zentara@zentara:~/1 > find . -name '*.jpg' ./trash.jpg ./linus1.jpg ./flag.jpg ./linus.jpg ./dobears.jpg zentara@zentara:~/1 > find . -name \*.jpg ./trash.jpg ./linus1.jpg ./flag.jpg ./linus.jpg ./dobears.jpg zentara@zentara:~/1 > -- $|=1;while(1){print pack("h*",'75861647f302d4560275f6272797f3');sleep(1); for(1..16){for(8,32,8,7){print chr($_);}select(undef,undef,undef,.05);}}
On Monday 25 March 2002 23.20, zentara wrote:
zentara@zentara:~/1 > ls dobears.jpg flag.jpg frontpage.bmp hula.gif linus.jpg linus1.jpg mscement.png oldglory.ps trash.jpg tuxvolt_a.gif
zentara@zentara:~/1 > find . -name "*.jpg" ./trash.jpg ./linus1.jpg ./flag.jpg ./linus.jpg ./dobears.jpg
zentara@zentara:~/1 > find . -name '*.jpg' ./trash.jpg ./linus1.jpg ./flag.jpg ./linus.jpg ./dobears.jpg
zentara@zentara:~/1 > find . -name \*.jpg ./trash.jpg ./linus1.jpg ./flag.jpg ./linus.jpg ./dobears.jpg zentara@zentara:~/1 >
mkdir blah touch blah/blah.jpg and try again. //Anders
On Mon, 25 Mar 2002 23:38:20 +0100 Anders Johansson <andjoh@cicada.linux-site.net> wrote:
mkdir blah touch blah/blah.jpg
and try again.
OK, no difference on my machine. What is supposed to happen? I even made blah, blah.jpg, and blah/blah.jpg zentara@zentara:~/1a > ls blah blah.jpg dobears.jpg flag.jpg frontpage.bmp hula.gif linus.jpg monk.jpg oldglory.ps tux2.jpg zentara@zentara:~/1a > ls blah OldGlory.jpg blah.jpg frontpage.jpg linus1.jpg tux2.jpg tuxvolt_a.gif zentara@zentara:~/1a > find . -name "*.jpg" ./blah/blah.jpg ./blah/frontpage.jpg ./blah/linus1.jpg ./blah/OldGlory.jpg ./blah/tux2.jpg ./blah.jpg ./monk.jpg ./flag.jpg ./tux2.jpg ./linus.jpg ./dobears.jpg zentara@zentara:~/1a > find . -name '*.jpg' ./blah/blah.jpg ./blah/frontpage.jpg ./blah/linus1.jpg ./blah/OldGlory.jpg ./blah/tux2.jpg ./blah.jpg ./monk.jpg ./flag.jpg ./tux2.jpg ./linus.jpg ./dobears.jpg zentara@zentara:~/1a > find . -name \*.jpg ./blah/blah.jpg ./blah/frontpage.jpg ./blah/linus1.jpg ./blah/OldGlory.jpg ./blah/tux2.jpg ./blah.jpg ./monk.jpg ./flag.jpg ./tux2.jpg ./linus.jpg ./dobears.jpg zentara@zentara:~/1a > ---- $|=1;while(1){print pack("h*",'75861647f302d4560275f6272797f3');sleep(1); for(1..16){for(8,32,8,7){print chr($_);}select(undef,undef,undef,.05);}}
Hmmm. That's not supposed to happen!!! Hmmmm. "Conventional wisdom" says that the double-quotes don't protect the asterisk. However, reading the bash man-page we have: "Enclosing characters in double quotes preserves the literal value of all characters within the quotes, with the exception of $, `, and \. The characters $ and ` retain their special meaning within double quotes. The backslash retains its special meaning only when followed by one of the following characters: $, `, ", \, or <newline>. A double quote may be quoted within double quotes by preceding it with a backslash." Historically, this was not the case. At least as far as I remember. I just tested it on my system and the asterisk is not expanded before being passed to find. I then checked a Solaris system at work and it behaves like this as well (*not* expanding the asterisk). I guess there are a lot of UNIX old-timers here who are used to the way it **used to** work that we naturally assume that it still behaves like that. hmmmmm...... Regards, jimmo On Tuesday 26 March 2002 01:25, zentara wrote:
On Mon, 25 Mar 2002 23:38:20 +0100
Anders Johansson <andjoh@cicada.linux-site.net> wrote:
mkdir blah touch blah/blah.jpg
and try again.
OK, no difference on my machine. What is supposed to happen? I even made blah, blah.jpg, and blah/blah.jpg
zentara@zentara:~/1a > ls blah blah.jpg dobears.jpg flag.jpg frontpage.bmp hula.gif linus.jpg monk.jpg oldglory.ps tux2.jpg
zentara@zentara:~/1a > ls blah OldGlory.jpg blah.jpg frontpage.jpg linus1.jpg tux2.jpg tuxvolt_a.gif
zentara@zentara:~/1a > find . -name "*.jpg" ./blah/blah.jpg ./blah/frontpage.jpg ./blah/linus1.jpg ./blah/OldGlory.jpg ./blah/tux2.jpg ./blah.jpg ./monk.jpg ./flag.jpg ./tux2.jpg ./linus.jpg ./dobears.jpg
zentara@zentara:~/1a > find . -name '*.jpg' ./blah/blah.jpg ./blah/frontpage.jpg ./blah/linus1.jpg ./blah/OldGlory.jpg ./blah/tux2.jpg ./blah.jpg ./monk.jpg ./flag.jpg ./tux2.jpg ./linus.jpg ./dobears.jpg
zentara@zentara:~/1a > find . -name \*.jpg ./blah/blah.jpg ./blah/frontpage.jpg ./blah/linus1.jpg ./blah/OldGlory.jpg ./blah/tux2.jpg ./blah.jpg ./monk.jpg ./flag.jpg ./tux2.jpg ./linus.jpg ./dobears.jpg zentara@zentara:~/1a >
---- $|=1;while(1){print pack("h*",'75861647f302d4560275f6272797f3');sleep(1); for(1..16){for(8,32,8,7){print chr($_);}select(undef,undef,undef,.05);}}
-- --------------------------------------- "Be more concerned with your character than with your reputation. Your character is what you really are while your reputation is merely what others thing you are." -- John Wooden --------------------------------------- Be sure to visit the Linux Tutorial: http://www.linux-tutorial.info --------------------------------------- NOTE: All messages sent to me in response to my posts to newsgroups or forums are subject to reposting.
participants (6)
-
Anders Johansson
-
Clayton Cornell
-
James Mohr
-
Philipp Thomas
-
S.Toms
-
zentara