2

I have the following filepaths

/vol/form/various.txt
/vol/var/sender.py
/vol/var/hello.txt

I would like to get all .txt files that do not have the directory of form in them. For example, something like:

*.txt AND ! */form/*

What would be the correct globbing pattern to do this -- i.e, in a single pattern (or is that not possible)?

David542
  • 104,438
  • 178
  • 489
  • 842
  • 2
    With a combination of `globstar` and `extglob`, this glob might work: `**/!(form)/*.txt` – but I've seen `!(...)` be not very reliable; for example, if there is a text file in a subdirectory of `form`, it won't be excluded, and `**/!(form)/**/*.txt` matches everything. But if the `.txt` file is always directly in the `form` directory, it should work. – Benjamin W. Jun 28 '20 at 21:02
  • Thoughed of this, but seems too fragile – Gilles Quénot Jun 28 '20 at 21:15

2 Answers2

1

Like this:

find /vol ! -path '*/form/*' -type f -name '*.txt'

If you need to negate a pattern, like with a regex, AFAIK look around are not supported by find -regex*. So it's not possible only with one find regex expression.

Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
  • @Giles -- sure, is it possible to do it with just one `-path` argument? Or is the chaining necessary, that's basically my question. – David542 Jun 28 '20 at 19:55
  • You don't show us what you've tried, this is required for good quality question. Have you tested my solution ? It's a full working command. Dunno what you need more. It's exactly the purpose of your question – Gilles Quénot Jun 28 '20 at 19:57
  • @david542 -- yes I know it works, I was just wondering about the ability to do more complex patterns in a single pattern string. – David542 Jun 28 '20 at 19:59
  • 1
    This is not in your original question. Don't change the rules in comments: open a new question if this is not not sufficient – Gilles Quénot Jun 28 '20 at 20:02
1

You can negate a grep:

find /vol -type f -name '*.txt' | grep -v '/form/'

If you want a single regex you need to either find file names with find and feed to GNU grep:

find /vol -type f | ggrep -oP "(?!.*?\/form\/)(^.*\.txt$)" 

or use Perl with that same regex:

perl -MFile::Find -e 'find sub {
      print "$File::Find::name\n" if -f && m/(?!.*?\/form\/)(^.*\.txt$)/
      },"/vol/"'

Explanation of the regex:

(?!^.*?\/form\/)(^.*\.txt$)

^              ^                 Negative lookahead fail on /form/
                 ^       ^       Anchors for start and end of string
                   ^             all horizontal characters
                     ^^          literal . 
                                 (if not escaped it would match any character)
                       ^         txt extension 

Demo

dawg
  • 98,345
  • 23
  • 131
  • 206
  • Yes, but not in a _single expression_ or _single parrern_ like OP wrote – Gilles Quénot Jun 28 '20 at 20:24
  • 1
    If you can do it in a single regex expression, show us =) – Gilles Quénot Jun 28 '20 at 21:13
  • There you go! Possible but not elegant – dawg Jun 28 '20 at 21:23
  • Yes, not very obvious to re-use. What is `(^)` ? Don't get it – Gilles Quénot Jun 28 '20 at 21:56
  • @GillesQuenot the `^` would mean start of the string (`$` would mean end). I don't think it's required here since the filepaths are sort of self-contained and anchored by themselves. Is that what you mean? – David542 Jun 28 '20 at 22:01
  • @GillesQuenot here's an example: https://regex101.com/r/V4ag0W/2. If you remove the `^` it could match starting from halfway into the filepath, rather than from the start of the line. Try removing the `^` in he above regex (I had to do that myself to see what it was needed, or if it was just cosmetic). – David542 Jun 28 '20 at 22:04
  • @dawg how about this for the regex? `^(?!.*?\/form\/).*\.txt` -- https://regex101.com/r/V4ag0W/3 ? – David542 Jun 28 '20 at 22:04
  • It doesn't match the second line: https://regex101.com/r/V4ag0W/4 – Gilles Quénot Jun 28 '20 at 22:05
  • 1
    @It's not supposed to, the extension there is `.py` instead of `.txt`. – David542 Jun 28 '20 at 22:06
  • yea I'm not sure, I don't know perl, but using those same inputs in regex101 it looks ok. I would ask @dawg why. – David542 Jun 28 '20 at 22:49
  • I am not sure what that pastebin is showing. Check the regex on regex101 and it works as stated.... – dawg Jun 28 '20 at 22:58