How to Find Parent Directories Containing Multiple Specific Files/Directories Using tcsh


6 views

When dealing with complex directory structures in Unix-like systems, we often need to locate parent directories that contain all specified child items (files or directories). The conventional find command can identify directories containing any of the targets, but finding directories containing all specified items requires a more sophisticated approach.

Since the requirement specifies using tcsh, here's an efficient one-liner that works within this shell's constraints:

foreach dir (*)
    if (-d $dir && -e $dir/bar && -e $dir/baz && -e $dir/quux) then
        echo $dir
    endif
end

This solution:

  1. Iterates through all items in the current directory (foreach dir (*))
  2. Checks if each item is a directory (-d $dir)
  3. Verifies the existence of all required sub-items (-e $dir/bar etc.)
  4. Outputs matching directory names

If you can use find with some shell logic, this might be more efficient for deep directory trees:

find . -type d -exec sh -c '
    for dir do
        [ -e "$dir/bar" -a -e "$dir/baz" -a -e "$dir/quux" ] && echo "$dir"
    done
' sh {} +

For cases where the target files might change, consider this parameterized version:

set required_files = (bar baz quux)
foreach dir (*)
    if (-d $dir) then
        set has_all = 1
        foreach file ($required_files)
            if (! -e $dir/$file) then
                set has_all = 0
                break
            endif
        end
        if ($has_all) echo $dir
    endif
end

For large directory structures:

  • The find version will generally be faster as it doesn't spawn multiple processes
  • Avoid using backticks or command substitution which can be slow in tcsh
  • Consider directory depth when choosing between recursive and non-recursive solutions

When working with directory structures in Unix-like systems, we often need to find parent directories that contain ALL of a specified set of files or subdirectories. For example:

foo/
    bar
    baz
    quux
temp/
    bar

We want to identify foo because it contains all three specified items (bar, baz, and quux), but exclude temp which only contains one of them (bar).

Here's a one-line tcsh command that accomplishes this:

foreach d (*)
    if ( -d $d && -e $d/bar && -e $d/baz && -e $d/quux ) then
        echo $d
    endif
end

For more complex scenarios, you can combine find with logical operators:

find . -type d -exec sh -c '[ -e "$1"/bar ] && [ -e "$1"/baz ] && [ -e "$1"/quux ]' sh {} \; -print

To make it more flexible for different combinations of files/directories:

set required = (bar baz quux)
foreach d (*)
    set has_all = 1
    foreach req ($required)
        if ( ! -e $d/$req ) then
            set has_all = 0
            break
        endif
    end
    if ($has_all) then
        echo $d
    endif
end

For large directory trees, consider these optimizations:
- Use find with -prune to skip irrelevant directories
- Cache results if running multiple queries
- Process in parallel if supported by your system