14

I want to create a directory with a number at the end, e.x. "dir1", and increment that number if the directory already exists until it hits a directory name that doesn't exist, and I need to do this in a single line in a Linux command line, something like:

mkdir --increment dir$

How would I go about doing that?

So far I've got this:

dir=output; n=0; mkdir -p $dir$n; if test -d $dir$n; then n=$((n+1)); echo $dir$n; fi

But it just echos the next dir name, I need it to recursively execute the command.

5 Answers 5

26

This is a trivial exercise in the use of while:

n=0
while ! mkdir dir$n
do
    n=$((n+1))
done

But of course it doesn't take much thought to realize that this trivial mechanism doesn't scale well.

So instead of reinventing the wheel and having to shave off all of the corners again, one creates unique temporary directories from a template slightly differently:

name=$(mktemp -d dirXXXXXXXXXXX)

2
  • Binary search on the number might be good enough. Mar 3, 2014 at 11:53
  • There are quite a few corners to shave off from where you're starting in the wheel reinvention process, not the least of which are remembering the filesystem, considering security, and parallelization.
    – JdeBP
    Mar 3, 2014 at 13:40
7

If you just want to incrementally create directories that are listed in the correct order, may I instead recommend folders that are named based on the current date?

DATE=$(date +%F)
mkdir "dir-$DATE"

It will create directories with the names like dir-2014-03-02 (YYYY-MM-DD, so as to appear in alphabetical order).

If you create more than one directory per day, you can add the current time to the file name. See man date on how to tweak the output formatting of date.

6

find the "biggest" dirname first, get the number and increment that:

last_dir=(printf "%s\n" dir* | sort -Vr | head -1)
num=$(last_dir#dir)
mkdir "dir$((num+1))"
6
  • This is a good idea, but is not easy to parallize. Mar 3, 2014 at 11:54
  • Unless there are millions of directories, parallelization is definitely premature optimization. Mar 3, 2014 at 13:36
  • Why would you need printf here? Won't simple echo work?
    – Ruslan
    Mar 3, 2014 at 14:01
  • Also, I'd use dir[0-9]* instead of dir*.
    – Ruslan
    Mar 3, 2014 at 14:02
  • 1
    You misunderstand. I talk about whether the script is sensible to being run multiple times at once (multiple threads, multiple users etc) or not. Mar 3, 2014 at 14:04
3

Assuming your directories always start off at "dir1", and that there are no files named $dir* (iE they are all sequentially numbered directories), you can get away with this one liner -

mkdir ${dir}$(( `ls ${dir}* | wc -w` + 1 ))

This counts the number of files starting with $dir, then adds one to that number and creates a new file.

0

Addendum to the other answers: If you need the dirs to sort correctly by name, you may also want to pad the new dir number (NUM) with leading zeros to a fixed length.

The following could be condensed onto one line or embedded in one of the other solutions.

NUM="00"$NUM                  ## Left zero pad with fixed length - 1 zeros 
NUM=${NUM:((${#NUM} - 3)):3}  ## left trim to fixed length (3 in this case)

This assumes that NUM starts out at least 1 digit long and will not exceed the fixed length. Adjust accordingly to your requirements.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .