75

I am trying to list all the files from dir1, dir2, dir3 and dir4 which might be anywhere in as a sub directory of my cwd using the find command. I tried the following with no success:

find . -type f -regextype posix-egrep -regex 'dir1/.+|dir2/.+|dir3/.+|dir4/.+'

I tried posix-extended as well. How can I list these files?

1

7 Answers 7

103

And if you want to search three folders named foo, bar, and baz for all *.py files, use this command:

find foo bar baz -name "*.py"

so if you want to display files from dir1 dir2 dir3 use find dir1 dir2 dir3 -type f

try this find . \( -name "dir1" -o -name "dir2" \) -exec ls '{}' \;

4
  • I should have clarified. I might not have the path to the files I wish to search. I only know they are sub directories of the current dir.
    – Aaron
    Commented Jan 10, 2013 at 6:21
  • use ./dir instead of dir Commented Jan 10, 2013 at 6:24
  • The dir would still need to be in the cwd though, it may be two levels lower (e.g. ./path/to/dir1), in which case ./dir1 would not exist.
    – Aaron
    Commented Jan 10, 2013 at 6:28
  • edited the answer. Commented Jan 10, 2013 at 6:46
17

It's best to use the -path directive:

find .  \( -type f -and -path '*/dir1/*' -or -path '*/dir2/*' -or -path '*/dir3/*' -or -path '*/dir4/*' \)

Which means: find all files under current directory where there's 'dir1' or 'dir2' or 'dir3' or 'dir4' in the path.

1
  • You've got the parenthesis in the wrong place. See also -a and -o for the standard equivalent of GNU's -and/-or. Commented Sep 4, 2017 at 20:22
4

Just to let everyone know. Adding .*/ before each dir solved the problem since the regex is matching against the full path it seems.

4

This is my first idea after reading the previous answers:

find . -type f -regextype posix-egrep -regex ".*/(dir1|dir2|dir3|dir4)/.+"

This takes into account, that the regex must match the whole filename, and it is easier to understand.

0
2

Sample of fast(!) finding particular files (access_log) in multiple locations defined by wildcard (home directory) and general apache2 log directory applying also name filtering to exclude ssl logs and gzipped old logs. Does not directly answer the question here but might be userful for someone who found these instructions (like me).

find / \( -path "*var/log/apache2*" -o -path "*home/*/logs*" \) -type f  -name "*access_log" ! -name "*ssl*"

Be careful with spaces, specially near to \( and \).

By the way, I used it for apachetop, to find most active websites in my server.

apachetop -d1 -s9 -p $(find / \( -path "*var/log/apache2*" -o -path "*home/*/logs*" \) -type f  -name "*access_log" ! -name "*ssl*" -print | sed 's/^/-f '/)
2

you dont need to specify dir1 to dir4 by name if you are using regextype

find . -type f -regextype sed -regex ".*/dir[1-4]/[^/]*"
  • type f: find files not directories
  • regextype sed: uses sed regextype
  • regex: searches using regex in the entire path
  • ".*/dir[1-4]/[a-z0-9]*": .* at the beginning means any number of characters which could be of type (char/number/backslash(/) etc); dir[1-4] means look for "dir" followed by a number between 1 and 4; /[^/]* states that following dir1-4 omit any pathnames which have / in them, so it only returns files in the directory dir1-dir4 and ignores any subdirectories that may be within dir1-dir4.

created a directory for you to test it out: https://github.com/alphaCTzo7G/stackexchange/tree/master/linux/findSolution04092017

7
  • (1) We may never know Aaron's exact situation or requirements, but other answers have made the prudent decision that he has four directories, whose names are unspecified.   (They could be red, green, blue and yellow, or they could be John, Paul, George and Ringo.)   Your answer assumes that they are literally dir1, dir2, dir3 and dir4. … (Cont’d) Commented Sep 4, 2017 at 20:32
  • (Cont’d) …  (2) Why do you assume that Aaron doesn’t want to search subdirectories?  He seems to be saying that he does.  (3) Why are you restricting the search to files whose names contain only lower-case letters and digits (excluding things like foo_bar, foo.txt and FOO)?  (4) Why does your text explain /[^/]* when your answer doesn’t use it? Commented Sep 4, 2017 at 20:32
  • Hi Scott, thats for your comment.
    – alpha_989
    Commented Sep 4, 2017 at 21:12
  • (1-3). he mentions "I am trying to list all the files from dir1, dir2, dir3 and dir4" which might be anywhere in as a sub directory of my cwd, which means that dir1-dir4 might be anywhere, but he wants to find file right within dir1-dir4. ofcourse, if its not dir1-dir4, you have to change it to the specific names using red\|blue\|green\| etc..
    – alpha_989
    Commented Sep 4, 2017 at 21:12
  • 4. typo there.. I used [a-z0-9]* before..then realized [^/]* is shorter and more inclusive..forgot to change it when I posted this. Thanks for your careful comments.
    – alpha_989
    Commented Sep 4, 2017 at 21:15
1

I know you specified that using find, but only to show other options that can be used, you can use xargs:

find . -type d | grep -E "dir1$|dir2$" | xargs ls  

find . -name "dir1" -or -name "dir2" | xargs ls

You can have a file named "folders" that contains something like:

$ cat folders
dir1
dir2
dir3
dir4

Then, you can do something like this:

$ cat folders | xargs -I % find . -type d -name % | xargs ls
./Documents/dir1:
file1  file2  file3  file4

./Documents/dir2:
file1  file2  file3  file4

./Documents/dir3:
file1  file2  file3  file4

./Documents/dir4:
file1  file2  file3  file4

xargs in my opinion, I feel more versatile than find -exec. Also you can make some crazy stuff like

$ cat << EOF | xargs -I {} find ~ -name "{}" | xargs ls
> dir1
> dir2
> dir3
> EOF
/home/user/Documents/dir1:
file1  file2  file3  file4

/home/user/Documents/dir2:
file1  file2  file3  file4

/home/user/Documents/dir3:
file1  file2  file3  file4
3
  • Downvoted because in addition of all the issues you can have by using ls, this has a worse performance and doesn’t allow to filter on simple files like find’s type f does.
    – bfontaine
    Commented Feb 22 at 18:17
  • @bfontaine This answer was made long ago, I put my dedication and time into this answer, is funny, is not the accepted one, and you don't add anything. You just downvoted cuz you wake up ready to be a jerk. If you want "good performance" write your utility in Rust
    – Cuauhtli
    Commented Feb 23 at 13:56
  • I upvote good answers and I downvote the incorrect ones, and I also take the time to explain why I downvote because I know it’s annoying to see downvotes without knowing why. Next time should I downvote without commenting, so I don’t get insulted?
    – bfontaine
    Commented Feb 23 at 20:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .