12

I need to find an image, say ABC.jpg, that I know will have been programmatically placed into a directory named ABC_MPSC. I've tried:

cd /
find . -name "ABC_MPSC/ABC.jpg"

But that doesn't return anything (I actually know where the particular one I'm searching for is, so I know it exists). Is there a find command that could allow me not have to search manually?

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
bitmaker
  • 287
  • Very similar: https://unix.stackexchange.com/q/342392/117549; also: https://unix.stackexchange.com/q/352844/117549 – Jeff Schaller Mar 29 '19 at 18:31
  • 2
    You can also find it using locate, which should be significantly faster, but only works if the file already existed when updatedb was last run. – Simon Richter Mar 29 '19 at 20:01

2 Answers2

17

There's a -path predicate that's useful here:

find . -path '*/ABC_MPSC/ABC.jpg'

The POSIX description for that predicate is:

The primary shall evaluate as true if the current pathname matches pattern using the pattern matching notation described in Pattern Matching Notation. The additional rules in Patterns Used for Filename Expansion do not apply as this is a matching operation, not an expansion.

The reason that your -name "ABC_MPSC/ABC.jpg" failed is because the -name predicate:

shall evaluate as true if the basename of the current pathname matches pattern

In other words, -name never sees the directory of the current filename, only the base filename itself (ABC.jpg, for example).

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
10

Two ways (apart from using -path):

  1. Look for the directory, then detect the file:

    find / -type d -name 'ABC_MPSC' -exec test -f {}/ABC.jpg \; -print
    

    This relies on the find implementation to expand {} to the current pathname of the found directory, even though it's concatenated with /ABC.jpg (it's not required to do that). It could also be written as

    find / -type d -name 'ABC_MPSC' \
        -exec sh -c 'test -f "$1"/ABC.jpg' sh {} \; -print
    
  2. Look for the file, then check it's parent directory name:

    find / -type f -name 'ABC.jpg' -exec sh -c '
        case $(dirname "$1") in
            */ABC_MPSC) exit 0 ;;
            *) exit 1
        esac' sh {} \; -print
    

Both of these alternatives would be slower than using -path in the way as Jeff shows. I'm leaving them here as examples none the less, as they could possibly be adapted for other things.

Kusalananda
  • 333,661