glowblue
glowblue

Reputation: 23

Recursively find filenames of exactly 8 hex characters, but not all 0-9, no lookahead (Mac terminal, bash)

I'm trying to write a regex to find files recursively with Mac Terminal (bash, not zsh even though Catalina wants me to switch over for whatever reason) using the find command. I'm looking for files that are:

In other words, it would match A1234567, ABC12DEF, 12345ABC, and ABCDABCD, but not 12345678 or 09876543.

To find files that are exactly 8 hex digits, I've used this:

find -E . -type f -regex '.*/[A-F0-9]{8}'

The .*/ is necessary to allow the full path name to precede the filename. This is eventually going to get fed to rm, so I have to keep the path.

It SEEMS like this should work to fulfill both of my requirements:

find -E . -type f -regex '.*/(?![0-9]{8})[A-F0-9]{8}'

But that returns an error:

find: -regex: .*/(?![0-9]{8})[A-F0-9]{8}: repetition-operator operand invalid

It seems like the find command doesn't support lookaheads. How can I do this without one?

Upvotes: 2

Views: 319

Answers (3)

oguz ismail
oguz ismail

Reputation: 50750

With any POSIX-compliant find

find . -type f                 \
       -name '????????'        \
     ! -name '*[![:xdigit:]]*' \
       -name '*[![:digit:]]*' 

And if you insist on using regexps for this, here you go

find -E . -type f                     \
          -regex '.*/[[:xdigit:]]{8}' \
        ! -regex '.*/[[:digit:]]*'

Those who use GNU find should drop -E and insert -regextype posix-extended after paths to make this work.

Upvotes: 2

Paul Hodges
Paul Hodges

Reputation: 15273

My find didn't understand -E and was inexplicably grumpy about -regex in general, but this still worked:

find . -type f -name '[A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9]' -a -name '*[A-F]*'

Not as elegant as oguz ismail's, but easier to read for my clogged brain, lol

Upvotes: 0

Colin Fraizer
Colin Fraizer

Reputation: 582

It's probably easiest to just filter out the results you don't like:

find -E . -type f -regex '.*/[A-F0-9]{8}' -print | egrep -v '.*/[0-9]{8}$'

$ find -E . -type f -regex '.*/[A-F0-9]{8}' -print
./01234567
./ABCDEFAF
./ABCDEF01
./ABCDEF2A
./ABCDEFA2
./x/01234567
./x/ABCDEFAF
./x/ABCDEF01
./x/ABCDEF2A
./x/ABCDEFA2
$ find -E . -type f -regex '.*/[A-F0-9]{8}' -print | egrep -v '.*/[0-9]{8}$'
./01234567
./ABCDEFAF
./ABCDEF01
./ABCDEF2A
./ABCDEFA2
./x/01234567
./x/ABCDEFAF
./x/ABCDEF01
./x/ABCDEF2A
./x/ABCDEFA2

Upvotes: 0

Related Questions