'Add leading zeros to integer section of filename

I have folders of images with names like HolidaySnapsJune-1.tif , HolidaySnapsMay-12.tif and HolidaySnaps2018-005.tif

I want to add one leading 0 to the integer section of the filename if it is 2 digits long, and I want to add two leading 00s if it is just one digit long.

I have tried variations of

find . -name '*\_[0-9][0-9].tif' -exec sh -c '
for fpath do
  echo mv "$fpath" "${fpath%/*}/${fpath##*/}"
done' _ {} +

But these put the leading zeros in front of the full file name instead of in front of the integer section.

I would love to do this is a bash script which would recursively work on folders so it's important that the difference in names preceeding the '-' is ignored or worked-around.

I'm on Windows and just have access to whatever is built into git-bashso bash, sed, awk etc.



Solution 1:[1]

You could use the rename.ul command from linux-utils.

rename [options] expression replacement file...

replaces the first occurence of expression by replacement in all names of files passed to the command.

Assuming your filenames contain exactly one hyphen -, you could simply run both of the following commands in a shell that supports the **/* glob syntax (alternatively, use find with the -exec option or something alike) to recursively rename all files:

rename.ul -- - -00  **/*-?.tif
rename.ul -- - -0  **/*-??.tif

There are several options to rename.ul to prevent you from accidentally renaming unintended files (Watch out! The consequences could be quite drastic):

-v, --verbose
       Show which files were renamed, if any.

-n, --no-act
       Do not make any changes; add --verbose to see what  would
       be made.

-i, --interactive
       Ask before overwriting existing files.

So you could either run the commands with the -nv options to perform a dry-run and see what changes the program would make, or add -i to be asked for confirmation each time a file would be renamed.

Solution 2:[2]

If you don't want to use non-standard commands and write a small script, this would be one way to do it.

while read -r line; do
    num=$(sed 's/\..*//' <<<${line/*-})
    printf -v new_name '%s-%03d.%s' "${line/-*}" "${num}" "${line/*\.}"
    mv -v "${line}” "${new_name}"
done < <(printf '%s\n' HolidaySnapsJune-1.tif HolidaySnapsMay-12.tif)

Using HolidaySnapsJune-1.tif for explanation below:

  • ${line/*-} removes everything before the dash -= 1.tif
  • ${line/*\.} removes everything besides the extension.
  • sed 's/\..*//' <<<${line/*-} also removes everything after the first period ., so now we have simply 1
  • '%s-%03d.%s' the %03d part of that tells printf to print digits with leading zeroes up to 3 digits.

Used while read as it is easy to mockup with. You probably want to either use a find command or something such for the input to the loop.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Kaffe Myers