Issue
My goal is to automate the creation of multiple directories that end with numerical indexes: dir03 dir04 ... dir09
I tried the following command: mkdir dir0[3-9]
.
As the result, the shell created a directory named dir0[3-9]
I did try mkdir dir0{3,4,5,6,7,8,9]
. It works but it's less convenient.
What are the underlying reasons why mkdir dir0[3-9]
doesn't work as intended?
Solution
You got the syntax a bit wrong:
- You used
[3-9]
as used in pattern matching for matching an existing range of values (a range expression in globbing, used in filename expansion and a few other contexts, and also a range expression in regular expressions). - You need
{3..9}
as used in brace expansion for generating a new range of values (a sequence expression):
$ echo mkdir dir0{3..9}
mkdir dir03 dir04 dir05 dir06 dir07 dir08 dir09
remove the echo
when happy with the output.
So we use {3..9}
to generate a new range of values:
$ mkdir dir0{3..9}
$ printf '%s\n' {3..9}
3
4
5
6
7
8
9
and [3-9]
to match an existing range of values:
$ find . -name 'dir0[3-9]'
./dir03
./dir04
./dir05
./dir06
./dir07
./dir08
./dir09
$ printf '%s\n' {0..10} | grep '[3-9]'
3
4
5
6
7
8
9
Note that they look similar but the semantics are different between range expressions in brace expansion and pattern matching, for example in brace expansion {1..20}
expands to the numbers 1 through 20 (because ranges start/end with a potentially multi-digit number or a character) while in a range expression [1-20]
expands to just the 3 numbers 1, 2, and 0 (because ranges always start/end with a character, not a string nor a multi-digit number, and so it means the set of the digits 1-2 and the digit 0).
$ printf '%s\n' {1..20} | tr '\n' ' '
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
$ printf '%s\n' {1..20} | grep '[1-20]' | tr '\n' ' '
1 2 10 11 12 13 14 15 16 17 18 19 20
$ printf '%s\n' {9..20} | tr '\n' ' '
9 10 11 12 13 14 15 16 17 18 19 20
$ printf '%s\n' {9..20} | grep '[9-20]' | tr '\n' ' '
grep: Invalid range end
That last result is because the range in pattern matching always has to be increasing so 9-2
(the range before 0
in [9-20]
) is invalid in a regexp:
$ printf '%s\n' {9..20} | grep '[2-9]' | tr '\n' ' '
9 12 13 14 15 16 17 18 19 20
$ printf '%s\n' {9..20} | grep '[9-2]' | tr '\n' ' '
grep: Invalid range end
and in globbing:
$ ls -d dir0[2-9]
dir03 dir04 dir05 dir06 dir07 dir08 dir09
$ ls -d dir0[9-2]
ls: cannot access 'dir0[9-2]': No such file or directory
but is valid in brace expansion:
$ printf '%s\n' {2..9} | tr '\n' ' '
2 3 4 5 6 7 8 9
$ printf '%s\n' {9..2} | tr '\n' ' '
9 8 7 6 5 4 3 2
Answered By - Ed Morton Answer Checked By - Mildred Charles (WPSolving Admin)