Search code examples
bashshellglob

Regex with positive and negative selection in for loop to iterate through a list of files


I embarrassingly struggle to iterate through multiple files selected one the basis of multiple criteria (defined by a regex). For example from the files listed below I'd like to select only files with txt extension, except the ones containing a string "cat":

mousecatdog.txt
dogcowfox.gif
dogmousecat.txt
dogmousepig.txt

So I'd like to get only dogmousepig.txt from this list.

I tried to use negative lookaheads, but I am getting an error:

syntax error near unexpected token `('

Of course looked at other threads on the forum, and tried to fix the problem by adding parentheses () or enabling shopt -s extglob, but to no avail.

I'm using mac and the script is in bash.

 #!/bin/bash
    for FILE in ^((?!cat).)*.txt
     do
      printf "\$FILE\n" 
     done 

Solution

  • Bash uses wildcard expansion, not regular expressions in your example.

    I see two fairly easy solutions:

    1- use a wildcard for the positive selection and an RE for the negative selection, just like @Wiktor Stribizew said in his comment:

    for FILE in *.txt; do
       if [[ ! $FILE =~ cat ]]; then
          printf "$FILE\n" 
       fi
    done
    

    2- grep out the output of the wildcard expansion (although this won't work correctly if there are spaces in your file names):

    for FILE in `\ls -1 *.txt | grep -v cat`; do
       printf "$FILE\n"
    done