0

I have this working command line expression:

program --files path_to_mydir/mydata_[0-9].csv

I would like to go from [0-100] but this is not working.

program --files path_to_mydir/mydata_[0-100].csv

Also, bonus ask, what do you call [0-10] wrt shell scripting and bash scripts?

Thanks

Edit: while similar this question is not asking about ls

visc
  • 866
  • Regarding your "edit": The command used is irrelevant. It's the shell expanding the pattern on the command line before invoking the command. The fact that you use some generic program and the duplicate uses ls does not make the questions different in essence. – Kusalananda Apr 20 '21 at 12:53

2 Answers2

6

The [...] is a bracket expression. It matches a single character, always, so you can't use [0-100] as that would just match a single 0 or 1 (in the POSIX locale)

In the zsh shell, you could use <0-100> for a numerical range globbing pattern, but that won't work in bash:

program --files path_to_mydir/mydata_<0-100>.csv

In bash, you could use a brace expansion instead:

program --files path_to_mydir/mydata_{0..100}.csv

but you have to be aware of the difference between this and a filename globbing pattern. A brace expansion, as the one just above, generates strings, regardless of what filenames are available, while a filename globbing pattern matches existing names. This means that a brace expansion could potentially feed your program filenames that does not exist.

You could use [...] to match the files with numbers between 0 and 100, but you would have to make it three patterns, one for each length of numbers:

shopt -s nullglob

program --files
path_to_mydir/mydata_[0-9].csv
path_to_mydir/mydata_[1-9][0-9].csv
path_to_mydir/mydata_[1][0][0].csv

The first would match names containing the digits 0 through to 9, the second would match the names containing 10 through to 99, and the last would match the name containing 100.

Would you want to match zero-filled integers:

shopt -s nullglob

program --files
path_to_mydir/mydata_[0][0-9][0-9].csv
path_to_mydir/mydata_[1][0][0].csv

I set the nullglob shell option in both variations of this code to make sure that any pattern that is not matching any names is removed, and not left unexpanded.


User fra-san noticed that you could use a combination of the brace expansion above with something that would force the shell to trigger a globbing pattern match:

shopt -s nullglob
program --files path_to_mydir/[m]ydata_{0..100}.csv

The inclusion of [m] in the string (a pattern matching the character m) would force the shell to treat each of the strings that the brace expansion creates as a separate globbing pattern. Since we're using nullglob, the patterns that do not correspond to existing names would be removed from the argument list.

Note that this would generate and expand 101 globbing patterns, whereas the other approaches using globbing in this answer uses two or three patterns.

Kusalananda
  • 333,661
3

The [...] glob operator, like the similar regexp operator matches a character (or possibly collating element) in the specified set.

It only matches one character. Inside [...], you can have

  • individual characters, like [abc] which matches on either a or b or c
  • character classes, like [[:digit:]] which matches on characters for which isdigit() returns true.
  • ranges like [a-f] for characters (or collating elements) that sort in between a and f (beware it may and often does include more than just abcdef as things like é for instance fall in that range).
  • more esoteric ones like [[=e=]] equivalent classes, [[.x.]] a collating element given by name...

And you can combine all those. For instance [[:blank:][:digit:]a-f123] whould match on a character that is either a blank, digit, or sorts between a and f or is 1, 2 or 3.

Your [0-100] matches on a character that sorts between 0 and 1 or 0 or 0, so either one of 01٠۰߀०০੦૦୦௦౦౸೦൦෦๐໐༠༳၀႐០៰᠐᥆᧐᪀᪐᭐᮰᱀᱐⁰₀↉⓪⓿〇㍘꘠꣐꤀꧐꧰꩐꯰0 (or possibly more or less depending on the system, locale and version of bash).

To match on on a sequence of one or more characters that make up integer numbers 0 to 100 in decimal, you'd need to use extglob, and break it down as:

*(0)@(100|[123456789]?([0123456789]))

That is, any number of 0s followed by either 100 or a 1..9 digit optionally followed by a 0..9 digit.

Or you could switch to zsh which has a dedicated glob operator to match on strings that make up decimal integers: <0-100> here. In zsh, you can also use the n glob qualifier to make sure the files are ordered numerically so that 10 comes after 2 for instance:

program --files path_to_mydir/mydata_<0-100>.csv(n)