0

In Bash, I can specify filenames Foo1.png through Foo9.png using Foo[0-9].png. I can avoid Foo5.png using Foo[1-46-9].png. Is there any way to specify a series of exclusions for the decimal digit?

For example, if I wanted to exclude Foo3.png and Foo7.png, I could use Foo[0-24-689], but I would find a pattern like Foo[^37].png to be much easier to read. That's Vim syntax, and Bash doesn't interpret it excluding 3 and 7. But I was wondering if Bash does have a pattern for character exclusion in its filename expansion.

If there is a solution that matches all single characters other than 3 or 7, that would be helpful too, in some circumstances (such as the particular one that motivated this question, nowithstanding the overly simplified description above).

5
  • 1
    Foo[^37].png should work (at least in reasonably current versions of bash) although for POSIX compliance it would be Foo[!37].png Oct 31, 2021 at 22:19
  • 1
    steeldriver: That only works to a point, you’d still see Food.png, which I don’t think was the expectation. To the OP, how do you suppose that bash is going to infer your intention to match all numerics (and only numerics) except those specified, without being told?
    – bxm
    Oct 31, 2021 at 22:39
  • @steeldriver: That works for me. Would you post it as the answer, including bxm's caveat? As if often the case, after someone points out the "how", I am able to find it in the documentation. Oct 31, 2021 at 22:48
  • @bxm: As it turns out, steeldriver's solution works for my particular situation, even though it doesn't fully answer the question as described. The question is oversimplified. I added a paragraph indicating this. Oct 31, 2021 at 22:50
  • What I meant to say was that Foo[!37].png worked for me, but not Foo[^37].png. Based on they's answer below, however, I retried based on a new set of test files. Both formats work, so something else must have been not right in the attempts that motivated this question. Nov 1, 2021 at 18:38

1 Answer 1

3

The bash shell understands both the regular expression-like Foo[^37].png pattern and the standard shell pattern Foo[!37].png, so you would be able to use them without problem unless you have other files with names like Food.png or Fool.png etc. that you need to exclude.

If Foo[^37].png does not work as expected in your script, then this indicates that you are not using bash, but some other shell such as, e.g. dash (possibly on a non-GNU system?) Did you run the script with sh on the command line? If so, don't, and use a proper #!-line in the script pointing to the correct shell interpreter.

Assuming there are names like Food.png that you want to exclude, to make sure that you get Foo followed by a digit, then .png, then use Foo[0-9].png. To then exclude Foo3.png and Foo7.png from these, test these separately.

for name in Foo[0-9].png; do
    case $name in (*[37].png) continue; esac

    # process "$name" here
done

Or, using bash syntax,

for name in Foo[0-9].png; do
    [[ $name == *[37].png ]] && continue

    # process "$name" here
done

As Stéphane Chazelas mentions in the comments below, you may use an extended globbing pattern in bash to test for digits other than 3 and 7. Enable extended globbing patterns with shopt -s extglob, then use the pattern

Foo!(!([0-9])|[37]).png

But it would be quicker for me personally to write the script as in the first half of this answer (or use Foo[01245689].png for that matter), run it, and be done, before deciding that I believe that this expression is doing the right thing (it does).

12
  • Foo[^37].png would work in dash. The only shells I know where it doesn't work are the Bourne shell and ksh88 and bosh (both derived from the Bourne shell). (and fish, but that's because it doesn't support bracket expressions at all) Nov 1, 2021 at 6:52
  • Note that in bash (and most of the usual locales), [0-9] matches hundreds of different characters, not just 012345679 Nov 1, 2021 at 6:55
  • In bash -O extglob, see also !(!([0-9])|[37]) (which would be more like vim's [37]\@!\d) Nov 1, 2021 at 6:55
  • @StéphaneChazelas Foo[^37].png does "work" in dash but only if you want the files Foo3.png, Foo7.png and Foo^.png.
    – Kusalananda
    Nov 1, 2021 at 7:00
  • with what version of dash? Nov 1, 2021 at 7:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .