Unix find: list of files from stdin

2020-08-10 08:08发布

问题:

I'm working in Linux & bash (or Cygwin & bash).

I have a huge--huge--directory structure, and I have to find a few needles in the haystack.

Specifically, I'm looking for these files (20 or so):

foo.c
bar.h
...
quux.txt

I know that they are in a subdirectory somewhere under ..

I know I can find any one of them with find . -name foo.c -print. This command takes a few minutes to execute.

How can I print the names of these files with their full directory name? I don't want to execute 20 separate finds--it will take too long.

Can I give find the list of files from stdin? From a file? Is there a different command that does what I want?

Do I have to first assemble a command line for find with -o using a loop or something?

回答1:

If your directory structure is huge but not changing frequently, it is good to run

cd /to/root/of/the/files
find . -type f -print > ../LIST_OF_FILES.txt #and sometimes handy the next one too
find . -type d -print > ../LIST_OF_DIRS.txt

after it you can really FAST find anything (with grep, sed, etc..) and update the file-lists only when the tree is changed. (it is a simplified replacement if you don't have locate)

So,

grep '/foo.c$' LIST_OF_FILES.txt #list all foo.c in the tree..

When want find a list of files, you can try the following:

fgrep -f wanted_file_list.txt < LIST_OF_FILES.txt

or directly with the find command

find . type f -print | fgrep -f wanted_file_list.txt

the -f for fgrep mean - read patterns from the file, so you can easily grepping input for multiple patterns...



回答2:

You shouldn't need to run find twenty times.

You can construct a single command with a multiple of filename specifiers:

find . \( -name 'file1' -o -name 'file2' -o -name 'file3' \) -exec echo {} \;


回答3:

Is the locate(1) command an acceptable answer? Nightly it builds an index, and you can query the index quite quickly:

$ time locate id_rsa
/home/sarnold/.ssh/id_rsa
/home/sarnold/.ssh/id_rsa.pub

real    0m0.779s
user    0m0.760s
sys 0m0.010s

I gave up executing a similar find command in my home directory at 36 seconds. :)

If nightly doesn't work, you could run the updatedb(8) program by hand once before running locate(1) queries. /etc/updatedb.conf (updatedb.conf(5)) lets you select specific directories or filesystem types to include or exclude.



回答4:

Yes, assemble your command line.



回答5:

Here's a way to process a list of files from stdin and assemble your (FreeBSD) find command to use extended regular expression matching (n1|n2|n3).

For GNU find you may have to use one of the following options to enable extended regular expression matching:

-regextype posix-egrep

-regextype posix-extended

echo '
foo\\.c
bar\\.h
quux\\.txt
' | xargs bash -c '
IFS="|"; 
find -E "$PWD" -type f -regex "^.*/($*)$" -print
echo find -E "$PWD" -type f -regex "^.*/($*)$" -print
' arg0

# note: "$*" uses the first character of the IFS variable as array item delimiter
(
IFS='|'
set -- 1 2 3 4 5
echo "$*"   # 1|2|3|4|5
)


标签: bash unix find