I am new to this stackexchange group, and apparently I'm not allowed to comment, so I will have to phrase this as an answer:
Several of the solutions I see at the time I am posting this have race conditions that can cause problems.
E.g. incrementing a counter: more than one instance of the script may be running between the time you check -f $filename$i and the time you create such a file name if it does not already exist. In this instance since you are using >, one instance might be lost.
E.g. Placing a Timestamp in the filename: similarly, two instances may be running at precisely the same time, whatever granularity your time Sam indicates.
E.g. write into a temporary file name that is the same, and then moving it to a versioned file name… Similar problems.
Probably the most standard solution is to embed the process ID in the file name - eg it might look like base.seq#.timestamp.pid. Most UNIXes require the PID to be unique. ... until it gets recycled (unlikely). ... or if you are accessing a network file system, from separate OS instances that do not have the same process ID space. Add hostname as a bandaid? ... but host names are not necessarily unique, not even with full domains, nor are IP addresses with NAT or MAC numbers.. Even on a single system, sometimes people use their own user level cooperative multithreading libraries that the OS is not aware of... and, yes, some of them will permit you to do system calls.
The most general solution is something that removes the window/race condition: something that allows you to test that a filename$i already exists, and returns to a newly opened file descriptor if it does not. Atomically. But even if your OS supports that, nit all filesystems do. (One of the reasons why the "rename" approach is popular is that the rename() syscall when it was eventually added had better guarantees in this regard.)
Anyway, I would rather have made this a comment, because right now I cannot recall if there is a single BKM for UNIX families and in ubuntu in particular. As an old fogey I know that this has been a long-standing source of bugs, but I don't know if it has been completely resolved, particularly for the most general network and cloud file systems.
But having pointed out that there can be dragons here, I can backpedal and say that you can frequently get away with some of the solutions suggested by the answers that triggered my multiprocessor red flags, esp filename.timestamp.PID, in shell scripts if you know things about the environment, such as you are not running on a network filesystem. And especially if you know that you don't need to worry about DIY multithreading packages, only OS standard multithreading.
I hope that somebody will correct me by providing the guaranteed always to work on all Ubuntu / UNIX-like systems code sequence... with or without constraints wrt network filesystem or cloud file system or FUSE file system or…