2

I have a folder of numbered data files. I am trying to incrementally extract a predefined range of files. The range of files that I am looking for is predefined in two variables, ns and ne, which change as the code runs.

I have been attempting something like the following:

$ ns=0001
$ ne=0030

$ ls foo_{$ns..$ne}.nc

But this does not read {$ns..$ne} as a sequence, and returns the error:

ls: cannot access foo_{0001..0030}.nc: No such file or directory

If I type the same command, but with the numbers entered manually, I get a list of files with numbers ranging from 0001 to 0030 as expected.

I presume that I am making a fundamental error in the use of sequencing, but would appreciate someone informing me what this error is.

Many thanks.

  • The problem is that brace expansion happens before parameter expansion, so you can't use variables in the brace expansion. See http://mywiki.wooledge.org/BraceExpansion – Eric Renouf May 24 '16 at 15:32
  • eval "echo foo{$ns..$ne}" but uh you really want to use seq instead. – thrig May 24 '16 at 15:36

2 Answers2

3

Brace expansion happens before variable expansion, so there's no way to use variables in it. You can use seq instead:

seq -f foo_%03.0f.nc $ns $ne
choroba
  • 47,233
1

Note that {1..20} is not a wildcard/globbing operator. That's a special form of brace-expansion introduced by zsh and copied with limitations and variations by ksh93 and bash.

foo_{0001..0030}.nc doesn't expand to the list of matching files, it expands to foo_0001.nc, foo_0002.nc, ... foo_0030.nc regardless of whether the files exist or not.

bash has that limitation that the content cannot be variable. ksh93 and zsh don't have that limitation.

So ls -d foo_{$ns..$ne}.nc will work in those shells.

zsh also has a globbing/wildcard operator to match decimal number ranges.

ls -d foo_<1-30>.nc

Will expand to the list of matching files. If you want to limit it to 4 digit 0-padded ones, you'd need another operator:

ls -d foo_(<1-30>~^????).nc # needs extendedglob

(~ is except (and-not), ^ is not, so ~^ is and-not-not, so and).

The <x-y> operator doesn't work with variables though (because it overlaps with redirection operators, it only works when following the <[digits]-[digits]> pattern to avoid clashes with redirections as much as possible). You can however use this syntax to work around it:

ls -d ${~:-foo_<$ns-$ne>.nc}

Or more legibly:

pattern="foo_<$ns-$ne>.nc"
ls -d $~pattern