regex doesn't work with optional ()? sentense

Viewed 36

I try to get all files like scheme_12.sql and scheme_23_analytics.sql from folder with bash and regex works in a strange way in terminal, doesn't return anything. Also checked in python re and some interactive regex sites. It works.

my command ls | find . -type f -regex "\.\/scheme_[0-9]+_([a-zA-Z]+)?.sql"

but command without optional sentence works ls | find . -type f -regex "\.\/scheme_[0-9]+.sql"

I have no idea why. Can you help me find a mistake?

2 Answers

The default regex type doesn't support the construct. Use -regextype to specify a different one, posix-extended if available for example should support it.

Also, why do you pipe the output of ls to find? find doesn't need anything from standard input.

$ touch scheme_12.sql  scheme_23_analytics.sql
$ find . -type f -regextype posix-extended -regex "\.\/scheme_[0-9]+_([a-zA-Z]+)?.sql"
./scheme_23_analytics.sql

To get both the files back, you need to move the underscore inside the optional character class.

There are several issues:

  • You are using POSIX BRE pattern where the group syntax is \(...\), not (...) and + quantifier is usually written either as \{1,\} or re-written from a+ to aa*
  • The ([a-zA-Z]+)? part is equal to [a-zA-Z]*, and the underscore in front is still obligatory. You need to make the whole sequence of _ and letters optional
  • Literal dot before sql must be escaped, or it will match any char
  • The / char does not need to be escaped in find regex because it does not use regex delimiters.

Here is a POSIX ERE solution:

find . -type f -regextype posix-extended -regex '\./scheme_[0-9]+(_[[:alpha:]]+)?\.sql'

So, (_[[:alpha:]]+)? here defines an optional sequence of _ and one or more letters.

Related