I would like to create many directories using mkdir. Each directory name will consist of a prefix (a string) and an index (an integer). Suppose that I would like the prefix to be "s" and the indices to range from 1 to 50. This means that I would like to create directories titled:

s1, s2, ... , s49, s50

Is there a way to do this automatically using mkdir? Thanks for your time.

Zsh, ksh93 or bash make this much easier, but I should point out this is not built into mkdir and may not work in other shells. For larger cases, it may also be affected by limits on the number or total size of arguments that may be passed to a command.

+1 This is great! I gotta nitpick about one thing, though: n=$(( n + 1 )) would've been just as strictly POSIX and wouldn't cost you a subshell.
–
kojiroSep 21 '12 at 5:04

@rahmu the [[ keyword is not POSIX. (Not to mention that [is a shell builtin in many modern shells.)
–
kojiroSep 21 '12 at 12:03

@kojiro: [[ works on my ksh88 (which predates bash) so I assumed it was POSIX. I couldn't find any mention of it in the POSIX spec so I believe you're right. Thanks for the info!
–
rahmuSep 21 '12 at 12:23

I thought about adding a version using arithmetic expansion, but wanted to limit "pure sh" to stuff that would have worked on pre-POSIX versions as well. I also didn't mention seq for the same reason - if you have seq you probably have bash. The loop example is also good for bypassing argument limits for a larger number of directories, which also means there's a place for for i in {range} for users of advanced shells.
–
Random832Sep 21 '12 at 14:50

you may want to do more with $i than just make a directory e.g mkdir s$i ; echo $i > s$i/$i. Also, One is a nice, simple example of using a for loop in bash...on a site like this it's not at all unlikely for a novice user to see it and think "nice, i didn't realise you could do that" ---> enlightenment.
–
casSep 21 '12 at 2:47

or if you want zero-padded numbers (which would be better for sorting):

mkdir $(seq --format 's%02.0f' 1 50)

or:

mkdir s$(seq -s ' s' -w 1 50) -- note the string 's' just before the $(), without it the first directory created will be just '01' rather than 's01'

and, finally: mkdir $(printf "s%02i " $(seq 1 50))

seq is from GNU Coreutils

oddly, seq's --format or -f option only allows printf's floating point double types (like f and g. also a strange floating point hex format that i've never found any use for). I have no idea why. It would be nice if it also supported other printf(3) numeric types like integer (d,i), octal (o,U) or hex (x,X).

Anyway, a double format with 0 decimal precision like %.0f or %02.0f is close enough to an integer for this purpose.

$ seq --help
Usage: seq [OPTION]... LAST
or: seq [OPTION]... FIRST LAST
or: seq [OPTION]... FIRST INCREMENT LAST
Print numbers from FIRST to LAST, in steps of INCREMENT.
-f, --format=FORMAT use printf style floating-point FORMAT
-s, --separator=STRING use STRING to separate numbers (default: \n)
-w, --equal-width equalize width by padding with leading zeroes
--help display this help and exit
--version output version information and exit
If FIRST or INCREMENT is omitted, it defaults to 1. That is, an
omitted INCREMENT defaults to 1 even when LAST is smaller than FIRST.
FIRST, INCREMENT, and LAST are interpreted as floating point values.
INCREMENT is usually positive if FIRST is smaller than LAST, and
INCREMENT is usually negative if FIRST is greater than LAST.
FORMAT must be suitable for printing one argument of type `double';
it defaults to %.PRECf if FIRST, INCREMENT, and LAST are all fixed point
decimal numbers with maximum precision PREC, and to %g otherwise.

Lots of complicated answers here, but bash makes it really easy. Sure, the pure POSIX solution works, but why not take advantage of the bash shell you're using, anyhow? You can do this easily with brace expansion: