Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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.

share|improve this question
2  
Which shell are you using? –  Francesco Turco Sep 21 '12 at 12:54
    
@FrancescoTurco I'm using bash. Thank you for your time! –  Andrew Sep 21 '12 at 14:04
2  
FYI, I find it much more useful to use fixed-width indices, like: s01, s02, ... , s49, s50. If I used fixed-width indices, /bin/ls almost always produces the order I want. –  Rob Sep 21 '12 at 20:48

5 Answers 5

up vote 22 down vote accepted

You can do this with a shell script.

Pure sh - this will work even on pre-POSIX bourne shells:

n=1;
max=50;
while [ "$n" -le "$max" ]; do
  mkdir "s$n"
  n=`expr "$n" + 1`;
done

If you want to create a high number of directories, you can make the script faster by reducing it to a single call of mkdir as well as using shell builtins for testing and arithmetics. Like this:

n=1
max=50
set -- # this sets $@ [the argv array] to an empty list.

while [ "$n" -le "$max" ]; do
    set -- "$@" "s$n" # this adds s$n to the end of $@
    n=$(( $n + 1 ));
done 

mkdir "$@"

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.

mkdir s{1..50}
share|improve this answer
3  
+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. –  kojiro Sep 21 '12 at 5:04
    
@rahmu the [[ keyword is not POSIX. (Not to mention that [ is a shell builtin in many modern shells.) –  kojiro Sep 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! –  rahmu Sep 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. –  Random832 Sep 21 '12 at 14:50

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:

% mkdir -v s{1..10} && ls -1d s{1..10}                                   (09-24 17:37)
mkdir: created directory `s1'
mkdir: created directory `s2'
mkdir: created directory `s3'
mkdir: created directory `s4'
mkdir: created directory `s5'
mkdir: created directory `s6'
mkdir: created directory `s7'
mkdir: created directory `s8'
mkdir: created directory `s9'
mkdir: created directory `s10'
s1
s10
s2
s3
s4
s5
s6
s7
s8
s9
share|improve this answer
  • One

    for i in {1..50}; do
      mkdir s"$i"
    done
    
  • Two

    mkdir s{1..50}
    

    This option works in bash, zsh and ksh93

  • Three

    mkdir $(printf "s%02i " $(seq 1 50))
    
share|improve this answer
4  
Why would you ever use one over two? –  Kevin Sep 21 '12 at 1:46
5  
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. –  cas Sep 21 '12 at 2:47
    
-1 This does not work on my ksh88. –  rahmu Sep 21 '12 at 9:30
1  
@rahmu: I think one should only consider if jhonathan's answer fixes the problem with the OP's shell (bash), not necessarily with others. –  Francesco Turco Sep 21 '12 at 14:20
3  
@Kevin while it's not likely to be an issue for fifty, if you've got five hundred directories to make you might worry about argument limits. –  Random832 Sep 21 '12 at 14:49

Just to be different, here's a POSIX sh solution that uses recursion:

makedirs() {
  [ "$1" -gt 0 ] || return
  mkdir "s$1"
  makedirs $(( $1 - 1 ))
}
$ makedirs 9
$ ls
s1  s2  s3  s4  s5  s6  s7  s8  s9
share|improve this answer

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

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.

See also: http://www.gnu.org/software/coreutils/manual/html_node/seq-invocation.html

share|improve this answer
    
{1,50} or {01,50} (for zero-padding) is much easier and more understandable. –  Kevin Sep 21 '12 at 1:48
    
true...if you're using bash rather than sh. that's why i upvoted @Random832's answer. it's a good answer. using seq is also a useful answer. –  cas Sep 21 '12 at 2:27

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.