72

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?

Aaron
  • 1,497
  • 4
  • 14
  • 15
  • find . -type f -regextype sed -regex ".*/dir[1-4]/[a-z0-9]*".. shortest answer so far :) see answer below.. https://unix.stackexchange.com/a/390333/242983 – alpha_989 Sep 04 '17 at 20:12

7 Answers7

98

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 '{}' \;

harish.venkat
  • 7,313
  • 2
  • 25
  • 30
16

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.

4

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

Aaron
  • 1,497
  • 4
  • 14
  • 15
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.

Ronin Tom
  • 334
  • 1
  • 4
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

alpha_989
  • 433
  • 5
  • 8
  • (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) – Scott - Слава Україні Sep 04 '17 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? – Scott - Слава Україні Sep 04 '17 at 20:32
  • Hi Scott, thats for your comment. – alpha_989 Sep 04 '17 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 Sep 04 '17 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 Sep 04 '17 at 21:15
  • The answer has been updated. – alpha_989 Sep 04 '17 at 22:11
  • Well, you and I are interpreting the question differently.  But your comments prompted me to read the question for a fourth and fifth time, and I see now that your interpretation is plausible. – Scott - Слава Україні Sep 04 '17 at 22:19
2

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
Rui F Ribeiro
  • 55,929
  • 26
  • 146
  • 227
Cuauhtli
  • 121
  • 3