How to zero pad numbers in file names in Bash?

2020-01-27 11:41发布

What is the best way, using Bash, to rename files in the form:

(foo1, foo2, ..., foo1300, ..., fooN)

With zero-padded file names:

(foo00001, foo00002, ..., foo01300, ..., fooN)

标签: bash rename
9条回答
forever°为你锁心
2楼-- · 2020-01-27 12:01

In case N is not a priori fixed:

 for f in foo[0-9]*; do mv $f `printf foo%05d ${f#foo}`; done
查看更多
闹够了就滚
3楼-- · 2020-01-27 12:10

It's not pure bash, but much easier with the rename command:

rename 's/\d+/sprintf("%05d",$&)/e' foo*
查看更多
叼着烟拽天下
4楼-- · 2020-01-27 12:10

Pure Bash, no external processes other than 'mv':

for file in foo*; do
  newnumber='00000'${file#foo}      # get number, pack with zeros
  newnumber=${newnumber:(-5)}       # the last five characters
  mv $file foo$newnumber            # rename
done
查看更多
姐就是有狂的资本
5楼-- · 2020-01-27 12:11

I had a more complex case where the file names had a postfix as well as a prefix. I also needed to perform a subtraction on the number from the filename.

For example, I wanted foo56.png to become foo00000055.png.

I hope this helps if you're doing something more complex.

#!/bin/bash

prefix="foo"
postfix=".png"
targetDir="../newframes"
paddingLength=8

for file in ${prefix}[0-9]*${postfix}; do
  # strip the prefix off the file name
  postfile=${file#$prefix}
  # strip the postfix off the file name
  number=${postfile%$postfix}
  # subtract 1 from the resulting number
  i=$((number-1))
  # copy to a new name with padded zeros in a new folder
  cp ${file} "$targetDir"/$(printf $prefix%0${paddingLength}d$postfix $i)
done
查看更多
▲ chillily
6楼-- · 2020-01-27 12:13

The oneline command that I use is this:

ls * | cat -n | while read i f; do mv "$f" `printf "PATTERN" "$i"`; done

PATTERN can be for example:

  • rename with increment counter: %04d.${f#*.} (keep original file extension)
  • rename with increment counter with prefix: photo_%04d.${f#*.} (keep original extension)
  • rename with increment counter and change extension to jpg: %04d.jpg
  • rename with increment counter with prefix and file basename: photo_$(basename $f .${f#*.})_%04d.${f#*.}
  • ...

You can filter the file to rename with for example ls *.jpg | ...

You have available the variable f that is the file name and i that is the counter.

For your question the right command is:

ls * | cat -n | while read i f; do mv "$f" `printf "foo%d05" "$i"`; done
查看更多
成全新的幸福
7楼-- · 2020-01-27 12:14

My solution replaces numbers, everywhere in a string

for f in * ; do
    number=`echo $f | sed 's/[^0-9]*//g'`
    padded=`printf "%04d" $number`
    echo $f | sed "s/${number}/${padded}/";
done

You can easily try it, since it just prints transformed file names (no filesystem operations are performed).

Explanation:

Looping through list of files

A loop: for f in * ; do ;done, lists all files and passes each filename as $f variable to loop body.

Grabbing the number from string

With echo $f | sed we pipe variable $f to sed program.

In command sed 's/[^0-9]*//g', part [^0-9]* with modifier ^ tells to match opposite from digit 0-9 (not a number) and then remove it it with empty replacement //. Why not just remove [a-z]? Because filename can contain dots, dashes etc. So, we strip everything, that is not a number and get a number.

Next, we assign the result to number variable. Remember to not put spaces in assignment, like number = …, because you get different behavior.

We assign execution result of a command to variable, wrapping the command with backtick symbols `.

Zero padding

Command printf "%04d" $number changes format of a number to 4 digits and adds zeros if our number contains less than 4 digits.

Replacing number to zero-padded number

We use sed again with replacement command like s/substring/replacement/. To interpret our variables, we use double quotes and substitute our variables in this way ${number}.


The script above just prints transformed names, so, let's do actual renaming job:

for f in *.js ; do
    number=`echo $f | sed 's/[^0-9]*//g'`
    padded=`printf "%04d" $number`
    new_name=`echo $f | sed "s/${number}/${padded}/"`
    mv $f $new_name;
done

Hope this helps someone.

I spent several hours to figure this out.

查看更多
登录 后发表回答