3

This question already has an answer here:

I have some files named as A1.txt A2.txt ... A11.txt A12.txt, etc. I want to rename them to A0001.txt A0002.txt ... A0011.txt etc. Am I doing it right?

for file in A*.txt
do
mv ${file} ${file/-#.txt-/-"%5d".txt}
done

marked as duplicate by don_crissti, GAD3R, Anthony G - justice for Monica, Community Sep 16 '16 at 19:26

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • Quite logical. Unfortunately, no shell I know can interpret sprintf(3) patterns like "%5d". However, if you have GNU utilities on your system (which you probably do unless you are using BSD), check out man 1 printf or info -f coreutils printf. That might do what you want. Alternately, try @John1024's idea. – thb Sep 15 '16 at 23:40
  • Since the OP explained in a comment to an answer that he/she is using a Mac, the answers in the possible duplicate may not be relevant. I haven't used a Mac in years so I'm not sure. In any case, I edited the question to include the osx tag. – Anthony G - justice for Monica Sep 16 '16 at 11:21
  • @don_crissti You're right. I see that Gilles' answer actually had 4 solutions (including two that would work with Bash). – Anthony G - justice for Monica Sep 16 '16 at 11:35
6

If you don't have the prename option suggested by @John1024, you should be able to use the printf (a built-in in bash, but also available from GUN coreutils) to format the decimal digits with the desired field width and padding - unfortunately I don't think there's a one-step shell expansion to extract the digits, the closest I can get is

for file in A*.txt
do
  base="${file%.*}"
  printf -v newfile "A%04d.txt" "${base#A}"
  mv -- "$file" "$newfile"
done
  • I believe this is the best one can get with shell: +1. (The script could be made POSIX, if anyone so desired, by replacing fourth line with newfile=$(printf "A%04d.txt" "${base#A}")) – John1024 Sep 16 '16 at 0:27
  • @John1024 thanks for clarifying the POSIX option - I wasn't sure about that – steeldriver Sep 16 '16 at 0:53
  • Is base a keyword? Would you please explain what each line do? – Christin Sep 16 '16 at 7:34
  • @Christin base is just an arbitrary variable name - used to hold the original filename minus its extension, which is given by ${file%.*}. Then ${base#A} removes its leading A character, leaving just the digits, which we then print to a new filename using the desired format. – steeldriver Sep 16 '16 at 8:53
5

Using Perl's rename utility:

prename 's/(\d+)\./sprintf "%04d.", $1/e' A*.txt

prename is sometimes available under the name rename. There is, however, another unrelated and incompatible utility called rename that is installed by default on some distributions.

Debian-like distributions, among others, have Perl's rename/prename installed by default. If your distribution does not, instructions for installing it can be found here

(Hat tip to Steeldriver for improved version of the command.)

Example

Consider a directory with these files:

$ ls
A12345.txt  A123.txt  A12.txt  A1.txt

Now, let's run prename:

$ prename 's/(\d+)\./sprintf "%04d.", $1/e' A*.txt
$ ls
A0001.txt  A0012.txt  A0123.txt  A12345.txt

How it works

A single substitute command is used:

s/(\d+)\./sprintf "%04d.", $1/e
  • (\d+)\. matches one or more digits followed by a period. The digits are saved in group 1.

  • The final e tells perl to evaluate the command sprintf "%04d.", $1. This command returns the digits of group 1 in format %04d meaning zero-filled four digits, followed by a period.

  • @steeldriver Your sprintf suggestion is superior. Answer updated. – John1024 Sep 15 '16 at 23:47
  • Thank you for the response. When I do "man prename", there is a manual page. But when I run "rename 's/(\d+)\./sprintf "%04d.", $1/e' A*.txt", it says "command not found". I'm not sure why. – Christin Sep 15 '16 at 23:59
  • @Christin Curious. Try type prename and type rename. Also, what distribution/OS are you on? – John1024 Sep 16 '16 at 0:20
  • It says ' Command not found' for both prename and rename. I have a macintosh. Sorry I don't know what distribution means. – Christin Sep 16 '16 at 7:23
  • Christin: Hmm, that is not good. One option, according to this post, is to install rename via homebrew with: brew install rename. Another option, if you already have perl installed (I don't know what the default is on OSX), is to download the script ( wget 'http://www.perlmonks.org/?displaytype=displaycode;node_id=303814' -O rename ) and then install it on your path. If you are going to do a lot renaming, then rename does make things simpler. If not, then @steeldriver's solution is good. – John1024 Sep 16 '16 at 19:33

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