Search code examples
bashfilenamesglob

Bash: Expand braces and globs with spaces in filenames?


I have some files that look like:

/path/with spaces/{a,b,c}/*.gz

And I need all files matching the glob under a subset of the a,b,c dirs to end up as arguments to a single command:

mycmd '/path/with spaces/a/1.gz' '/path/with spaces/a/2.gz' '/path/with spaces/c/3.gz' ...

The directories I care about come in as command line params and I have them in an array:

dirs=( "$@" )

And I want to do something like:

IFS=,
mycmd "/path/with spaces/{${dirs[*]}}/"*.gz

but this doesn't work, because bash expands braces before variables. I have tried tricks with echo and ls and even eval (*shudder*) but it's tough to make them work with spaces in filenames. find doesn't seem to be much help because it doesn't do braces. I can get a separate glob for each dir in an array with:

dirs=( "${dirs[@]/#//path/with spaces/}" )
dirs=( "${dirs[@]/%//*.gz}" )

but then bash quotes the wildcards on expansion.

So: is there an elegant way to get all the files matching a variable brace and glob pattern, properly handling spaces, or am I stuck doing for loops? I'm using Bash 3 if that makes a difference.


Solution

  • Okay, so here is one using bash for the "braces" and find for the globs:

    find "${dirs[@]/#//path/with spaces/}" -name '*.gz' -print0 | xargs -0 mycmd
    

    Useful with this if you need the results in an array.