1

I have a directory with contents like the below example. I want to search subdir1, subdir2 & subdir3 for files testA/*a.txt, testB/*b.txt & testC/*c.txt. I want a list of all subdirectories only where all 3 exist.

In this example, that would be only subdir1 & subdir2.

subdir1/ subdir1/testA/ subdir1/testA/subdir1-a.txt subdir1/testB/ subdir1/testB/subdir1-b.txt subdir1/testC/ subdir1/testC/subdir1-c.txt subdir2/ subdir2/testA subdir2/testA/subdir2-a.txt subdir2/testB subdir2/testB/subdir2-b.txt subdir2/testC/ subdir2/testC/subdir2-c.txt subdir3/ subdir3/testA subdir3/testA/subdir3-a.txt subdir3/testB subdir3/testB/subdir3-b.txt subdir3/testC/ subdir3/testZ subdir3/testZ/subdir3-z.txt 

I want to then get the output in alphabetical order, e.g.:

subdir1 subdir2 

...and then get only the unique ones

(The need for this exists because I'm using find at the moment, and the directories are listed out of order. The subdirs also have longer/more complex names.)

How can I do this?

I've gotten so far as to list one type of file, e.g. the *-a.txt file, like this:

find . -wholename "**/testA/*a.txt

Apologies if the answer already exists somewhere, I looked but couldn't find one. Any advice would be much appreciated.

1 Answer 1

0

How about something like this:

$ shopt -s nullglob $ for dir in */; do f1=( "$dir"/testA/*a.txt ) f2=( "$dir"/testB/*b.txt ) f3=( "$dir"/testC/*c.txt ) if [[ "${#f1[@]}" -gt 0 && "${#f2[@]}" -gt 0 && "${#f3[@]}" -gt 0 ]]; then printf '%s\n' "$dir" fi done subdir1/ subdir2/ 

First, you turn on bash's nullglob option to make sure that globs that don't match any files expand to the empty string. Next, you iterate over all subdirectories in the current directory, and for each of them, you save the result of expanding the corresponding glob to an array. Then, if all three arrays have at least one element, print the name of the subdir.

You could do the same basic thing with find too:

$ for dir in */; do if [[ $(find "$dir" -wholename "*/testA/*a.txt" | wc -l) -gt 0 && $(find "$dir" -wholename "*/testB/*b.txt" | wc -l) -gt 0 && $(find "$dir" -wholename "*/testC/*c.txt" | wc -l) -gt 0 ]]; then printf '%s\n' "$dir" fi done subdir1/ subdir2/ 
3
  • Thanks! This helps, then how would I sort the output (list of subdirs with all these files) alphabetically, and find the unique list of all subdirs as determined by the first 7 characters? i.e. if I have subdir1a and subdir1b, I want only subdir1 as the output in the final list Commented Dec 7, 2022 at 10:29
  • @abra that... is a very different question. A simple way, assuming your directory names are simple ASCII and not UTF8 and that you want to sort according to your system's locale settings, would be to pass the output of either of the two commands above through | cut -c -7 | sort | uniq. Commented Dec 7, 2022 at 11:51
  • thanks, it worked! It was included in my main question, I wasn't sure how to integrate it. Marked your solution as accepted. Thanks again! Commented Dec 7, 2022 at 12:02

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.