Multidigit ranges of files in lexicographical order in zsh
Solution 1
[2-57]
is a character set consisting of 2
, 3
, 4
, 5
and 7
, in zsh and every other wildcard and regexp syntax out there. Your glob pattern *[2-57]
matches every filename whose last character is one of those five digits.
I think you are misremembering the syntax of the [m,n]
glob qualifier. Glob qualifiers always go in parentheses at the end of the pattern, and the range separator is a comma. The pattern *([2,57])
expands to the 2nd, 3rd, …, 57th matches. The default expansion order is lexicographic (with some special magic to sort numbers in numeric order if the numeric_glob_sort
option is set); you can control it with the o
or O
glob qualifier (e.g. *(om[2,57])
to match the 57 most recent file except the one most recent file).
for x in /foo/bar/*([2,57]); do print $x; done
Not what you asked for, but related and possibly useful to future readers: if you want to enumerate files 2 to 57 whether they exist or not, you can use a range brace expression. This feature also exists in bash and ksh.
echo hello{2..57}
And if you want to match files whose name contains a number between 2 and 57, you can use the pattern <2-57>
. This is specific to zsh.
$ ls
file1 file2 file3 file57 file58
$ echo file<2-57>
file2 file3 file57
Note that a pattern like *<2-57>
is likely not to do what you expect, because the *
could match digits too. For example, file58
matches *<2-57>
, with file5
matching the *
part and 8
matching the <2-57>
part. The pattern *[^0-9]<2-57>
avoids this issue.
Solution 2
but zsh apparently thinks I am asking for the files 2 to 5 (or something like that) instead of files 2 to 57. Any thoughts why?
Because []
brackets indicate a list of matched characters (which can be digits), not numbers interpreted mathematically. Such pattern is matched against a single character. The list can contain ranges, but of digits or letters. [2-57]
match expands to "All digits in the range from 2 to 5 and a 7".
To match numbers from 2 to 57, it would be easier to use a sequence expression instead of a globbing pattern (or together with such):
for x in /foo/bar/*{2..57}; do print $x; done
Edit: But this, unfortunately, will not give you lexicographical order of all listed files - they'd be grouped by common number endings due to shell expansion.
Related videos on Youtube
Amelio Vazquez-Reina
I'm passionate about people, technology and research. Some of my favorite quotes: "Far better an approximate answer to the right question than an exact answer to the wrong question" -- J. Tukey, 1962. "Your title makes you a manager, your people make you a leader" -- Donna Dubinsky, quoted in "Trillion Dollar Coach", 2019.
Updated on September 18, 2022Comments
-
Amelio Vazquez-Reina over 1 year
I would like to specify a range of files (in lexicographical order) with two integers (e.g. 2 to 57) in zsh by globbing.
For example: "pick the files 2 to 57 in lexicographical order under the path that matches some globbing pattern".
I thought using square brackets would do it
for x in /foo/bar/*[2-57]; do print $x; done
but zsh apparently thinks I am asking for the files
2
to5
(or something like that) instead of files2
to57
. Any thoughts why? How can I accomplish this? -
Amelio Vazquez-Reina over 12 yearsThanks @rozcietrzewiacz! I should have thought about that. My files had numbers in them, so for a moment I thought
[]
was printing things in order.. -
Gilles 'SO- stop being evil' over 12 yearsYour explanation of
[2-57]
is correct, but I don't think{2..57}
(that's what you meant, right?) is relevant to what intrpc wants to do, which is “pick the files 2 to 57 in lexicographical order”. -
rozcietrzewiacz over 12 yearsThanks for the edit (time to go to sleep, I guess). And you're right - I'd forgotten about the lexicographical order part.
-
Amelio Vazquez-Reina over 12 yearsYou are right. I was misremembering the glob qualifier. Thanks for the careful explanation.
-
Gilles 'SO- stop being evil' over 12 years@intrpc
foo{8..11}bar
expands tofoo8bar foo9bar foo10bar foo11bar
. This bit of expansion is unrelated to file names. Similarly,foo{eight,nine,ten,eleven}bar
expands tofooeightbar fooninebar footenbar fooelevenbar
. This is brace expansion in ksh/bash/zsh.