How to rename multiple files sequentially from command line?

The rename tool that ships with Ubuntu is pretty hot at this sort of stuff. You can embed little Perl expressions like so:

rename -n 's/.+/our $i; sprintf("AS%d.txt", 1+$i++)/e' *

That will just show you what it would do. Remove the -n to make it a live-fire exercise.

This basically works by rough-defining a variable and incrementing it each file we hit. If you're going to have more than 10 files, I suggest using some zero-padding in the sprintf. The following is good up to 999:

rename -n 's/.+/our $i; sprintf("AS%03d.txt", 1+$i++)/e' *

... But that's easy enough to expand.


I don't know of a single command or utility that would do this, but it's easy enough to do with a simple loop:

N=1
for X in AS*RAW*; do
  mv $X AS$N.txt
  N=$(($N+1))
done

To improve on @Oli's answer, the rename tool version 1.600 by Aristotle Pagaltzis actually has a counter built in, $N.

So all you need is,

rename 's/AS.*/AS$N/' *

To install,

  1. brew install rename or Download the script
  2. Save it to a directory on your system path (usually /usr/local/bin/brew or /usr/bin)

rename lets you assign directly to $_, which is ideal for this problem.

Although the code arguments we pass to the Perl rename utility often perform matching and substitution (with s/), and it is totally acceptable to solve this problem that way, there's really no need for that in cases like this one where you're not actually examining or reusing the text of the old filenames. rename lets you write just about any Perl code, and it doesn't need to be embedded inside s/ /e. I suggest using a command like this:

rename -n 'our $i; $_ = sprintf "AS%02d.txt", ++$i' *

Or, if you feel like shaving off a few characters:

rename -n '$_ = sprintf "AS%02d.txt", ++our$i' *

(It could be made even shorter, but not without sacrificing clarity.)

Both those commands do the same thing. Each shows what renaming operations would be undertaken. Once you try one out and you're happy with the results, run it again without the -n option. As written, this would produce the filenames AS01.txt, AS02.txt, ..., AS10.txt, AS11.txt, and so on. You can modify them as needed, then only remove -n when you like what you see.

If you want to pad to a greater width than 2, replace the 2 with a bigger number. For example, if for some reason you wanted filenames like AS00000000000001.txt, you would replace %02d with %014d. If you don't want padding at all--even though that would make your files appear in non-numeric order when you list them later!--then you can replace %02d with just %d.

How does this work? Your shell expands * into a list of files before it even runs the rename command. The list is sorted lexicographically (i.e., alphabetically) according to your current locale settings. rename receives the filenames as command-line arguments and processes them in the order they are listed. The expression ++$i evaluates to one greater than the current value of the variable $i, and also sets the variable $i to that newly incremented value. This value is passed to sprintf, which formats it and places it inside other text. This text is assigned directly to the special variable $_, which holds the filename. Since the rename processes files in the order they are passed as arguments, they are numbered accordingly.


You may have noticed the similarity to Oli's answer!

Both declare and increment a counter variable, and both use sprintf in essentially the same way to embed the value of that counter, padded on the left with zeros, in the other text of the new filenames. (The information in either answer about how to pad with zeros--and change the padding width--even applies equally to both.) The reason they are so similar is that the method in that older answer is really doing just this1, but with extra steps that are useful for many problems but not actually necessary for this one.

For comparison, here's what the second command in that answer looks like if modified to use the style I've used here (and to pad to a width of 2, as I've done here, instead of 3):

rename -n 's/.+/our $i; sprintf "AS%02d.txt", ++$i/e' *

The part between s/.+/ and /e in that command is now the same as the expression I assign to $_ (i.e., the code on the right side of the = operator) in the first command in this answer.

  • The s/ operator attempts to match text (filenames that your shell expanded from * and passed as command-line arguments when it ran rename) with a regular expression, and performs substitution. / is being used as a delimiter to separate the different parts of the s expression. The first part, .+, is the regular expression; it matches any1 character (.), and does so one or more times (+). Since filenames are never empty--they're always at least one character long--this is one way to match any1 filename.
  • Then it produces text from each match--that is, from each whole filename--consisting of our $i; sprintf "AS%02d.txt", ++$i. This produces the new filename. Typically, one uses s/ to produce text that is either (a) replacing text that matched just part of the filename, or (b) based on the the matched text in some way (for example, it might use a special variable like $& that expands to the match). In this case, though, the matched text is not being used at all.
  • Normally the substituted text our $i; sprintf "AS%02d.txt", ++$i would be used as a filename, not run as code. But the /e flag at the end causes that text to be treated as Perl source code and evaluated, and uses the value produced by doing so (in this case, the return value of Perl's built-in sprintf function) as the new filename.

Although I think the method I've shown here is a clearer and simpler approach for this problem than any method that uses s/ with /e, it's good to be aware of that technique, because it is well suited to a number of other file renaming problems where all or part of the original filenames is examined and/or retained. I recommend this blog post by Oli (who also wrote that answer), which includes some such examples.

1Technically, there is a difference in the behavior of the $_ = commands and the s/ /e commands. In the regular expression .+, it's not strictly true that . matches any character, because it does not match a newline. You very probably shouldn't use filenames with newlines in them, but you can, and occasionally a file gets named that way by accident. If you feel like it, contrast the output of rename -n 'our $i; $_ = sprintf "AS%02d.txt", ++$i' $'foo\nbar' to that of rename -n 's/.+/our $i; sprintf "AS%02d.txt", ++$i/e' $'foo\nbar'. To make . match a newline, use the s flag, which goes at the end (with e). That is, write /se at the end instead of /e.


Though the OP requires a command line option, it is also available as a GUI option in Nautilus and is quite easy.

Select all the required files and press F2. There is an option called Automatic Numbers. You can append it to the text that you need.