2

This is syntactically correct:

for f in *bw;do echo $f;done

But How would I add an extension to loop through one or the other?

  • The following doesn't work:
    for f in *bw|*txt;do echo $f;done
    
  • And this doesn't work either:
    for f in *bw or *txt;do echo $f;done
    
2
  • 3
    What is the reason why for f in *bw *txt;do echo $f;done is not what you want?
    – Philippos
    Oct 19, 2021 at 6:37
  • I don't see why you need a loop at all: printf '%s\n' *bw *txt, unless you rely on the fact that the (bash) shell would perform splitting and globbing of your unquoted variable.
    – Kusalananda
    Oct 19, 2021 at 19:31

2 Answers 2

8

You don't. You iterate over both "extensions" and (if you need to) check if either or both exist. e.g. if you only want to print one or the other (the first one seen), keep a list of the basenames (without extensions) of each file - an associative array is useful for this because it's easy to look up. e.g. in bash:

declare -A files

for f in *.bw *.txt; do
  bn=${f%.*}
  if [ -z "${files[$bn]}" ] ; then
    echo "$f"
    files["$bn"]=1
  fi
done
6

In Bash, with shopt -s extglob, and also zsh with KSH_GLOB enabled:

for f in *.@(bw|txt)

Note that in bash, if there are no matches, the loop will run with $f set to the literal string *.@(bw|txt). To avoid this, in bash:

shopt -s nullglob
for f in *.@(bw|txt)

In zsh, by default, you'll get an error if there are no matches. To avoid this, add the N glob qualifier.

for f in *.@(bw|txt)(N)

In zsh, there's a simpler solution that works with default options, again with (N) to do nothing if there are no matches:

for f in *.(bw|txt)(N)

All of those will order all the entries alphabetically, with files with both extensions intermingled (that is, duplicate names that differ only in the extensions will (likely¹) be consecutive). You can list as many pipe-separated pattern entries within the parentheses as required, and they can include further globs (e.g. (zip|tar.?z)).


¹ foo.bw foot.bw foot.txt foo.txt however would sort in that order in locales where . is ignored in first instance in the collation algorithm as is common these days (as footb or foott come before footx and after foobw).

1
  • 2
    and on Bash, maybe shopt -s nullglob, so it doesn't run the loop with f set to literally *.@(bw|txt) if no matching files exist.
    – ilkkachu
    Oct 19, 2021 at 8:28

You must log in to answer this question.

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