Bash – Deduplicating Bash Brace Expansions

bashbrace-expansionwildcards

Brace expansions can produce multiple instances of file names if there is an overlap in the matches.

A simple example:

mkdir testdir; cd testdir
touch abcd
for f in *{b,c}*; do something_to "$f"; done
# or more simply:
ls -l *{b,c}*

That is a very simplified example just for illustration. In this case, the single file abcd would be processed (or listed) twice.

How can this list be best deduplicated?

  • An associative array could be used.
  • A carefully crafted glob/brace expansion could be used, but that's not robust.

Best Answer

Yes,

for f in *{b,c}*

is first expanded to:

for f in *b* *c*

And then the loop runs over the independent expansion of those two globs.

What you want here is one glob. Here, *[bc]* would do, but for anything more complex, in bash, you'd need to enable ksh-like extended globs. You'll probably want the nullglob option as well:

shopt -s nullglob extglob
for f in *@(b|c)*; do...

In zsh:

for f in *(b|c)*(N); do

The (N) being for a per-glob nullglob.

In ksh93:

for f in ~(N)*@(b|c)*; do