4

I am trying to add sequential four digit numbers to the end of file names during a rename script. The problem I am running into is that it only pads the first file and the numbers added are not sequential. Here is my script so far:

Starting file names:

FILE-1.png
FILE-5.png
FILE-14.png
FILE-99.png
FILE-167.png
FILE-199.png
FILE-278.png
FILE-455.png

Script:

a=`printf '%04d' "1"`

cd /${1-$PWD}

for i in *.png;
    do mv $i `printf output.%04d.$a.png $(echo $i | sed 's/[^0-9]*//g')`;
    let a=a+1 
done

EDIT: I changed the script a bit incorporating the fmt variable at the top. But I still would like it to name the second set of digits in numerical order of the first set of numbers, as in my Desired output below.

fmt=output.%04d
n=1

cd /${1-$PWD}

for i in *.png;
    do mv $i `printf $fmt.%04d.png $(echo $i | sed 's/[^0-9]*//g') "$n"`;
    n=$((n+1))
done

My new output:

output.0001.0001.png
output.0005.0007.png
output.0014.0002.png
output.0099.0008.png
output.0167.0003.png
output.0199.0004.png
output.0278.0005.png
output.0455.0006.png

Original output:

output.0001.0001.png
output.0005.7.png
output.0014.2.png
output.0099.8.png
output.0167.3.png
output.0199.4.png
output.0278.5.png
output.0455.6.png

Desired output:

output.0001.0001.png
output.0005.0002.png
output.0014.0003.png
output.0099.0004.png
output.0167.0005.png
output.0199.0006.png
output.0278.0007.png
output.0455.0008.png

As always any help is much appreciated!

VanCityGuy
  • 117
  • 1
  • 7
  • 2
    Not sure why somebody downvoted this. It has all the elements of a good question - input, desired and actual output, and even an attempt to code a solution. – ghoti Oct 11 '15 at 00:44

2 Answers2

1

So .. you're using printf for formatting. That's a good start. But you're not using it consistently. The part that's not formatted.. Why not just format it?

#!/bin/sh

fmt="output.%04d.%04d.png"

cd /${1-$PWD}

n=1
for file in *.png; do
    fn="${file%.*}"; fn="${fn#*-}"
    mv "$file" "$(printf "$fmt" "$fn" "$n")"
    n=$((n+1))
done

Note that the first line within the loop simply strips the number out of $file, first by taking off everything from the dot to the end, then by taking off everything from the start to the dash. You'll have to adjust this if your files are not actually formatted as they are in your question.

Oh, and Happy Thanksgiving. :-)


UPDATE per comments

The expansion above of *.png will obviously order things alphabetically, such that you FILE-5.png follows FILE-455.png, etc.

A number of tools can help you get a "natural" sort order. In particular, if you're using Linux, your ls and sort probably come from GNU coreutils, which means you can ls -v or sort -V to get a natural sort order. But you haven't specified that you're using Linux, and besides, parsing ls is a bad idea. But bash's internal pattern matching and pathname expansion does not handle natural sorts.

In this particular case, since you're dealing (at least in your question) with highly predictably formatted filenames, we can likely safely parse ls output and sort it using command line tools.

If you're using Linux and bash, the for line above can be replaced with:

shopt -s extglob
ls -v FILE-+([0-9]).png | while read file; do

This sets bash's extglob shell option, then uses ls -v (which is the Linux dependency) to show a restricted view of the files. When parsing ls, you don't want to make the mistake of constructs like *.png, as you don't want to have to spend time predicting what will happen if there's a newline inside a filename.

If you're using FreeBSD or OSX, or are not using bash, extra measures are required, as there is ls -v and no extglob in Almquish shell:

ls -f FILE-*.png | egrep '^FILE-[0-9]+\.png$' | sort -t- -k2n | while read file; do
  if [ ! -f "$file" ]; then
    continue
  fi

This breaks down as follows:

  • ls -f does no sorting on the directory. The filespec restricts the view somewhat.
  • grep is used to enforce filename format, as this pattern can't be represented completely in shell expansion.
  • sort -t- -k2n delimits fields with a hyphen, then sorts numerically on the second field.
  • The if inside the loop makes sure that we someone isn't screwing with us by making a filename like FILE-1.png\nFILE-2.png.
ghoti
  • 45,319
  • 8
  • 65
  • 104
  • 1
    Thank you for your help, however it doesn't seem to be working as desired. In line 10 I actually switched the order of "$n" and "$fn" but got this: `output.0001.testing4d.pngoutput.0001.testing4d.png` Note the script is save as testing.sh so it incorporating the script name into the renaming somehow. – VanCityGuy Oct 11 '15 at 18:16
  • Another thing is it is not keeping them sequential: `output.0001.testing4d.pngoutput.0001.testing4d.png` `output.0005.testing4d.pngoutput.0007.testing4d.png` `output.0014.testing4d.pngoutput.0002.testing4d.png` `output.0099.testing4d.pngoutput.0008.testing4d.png` `output.0167.testing4d.pngoutput.0003.testing4d.png` `output.0199.testing4d.pngoutput.0004.testing4d.png` `output.0278.testing4d.pngoutput.0005.testing4d.png` `output.0455.testing4d.pngoutput.0006.testing4d.png` – VanCityGuy Oct 11 '15 at 18:29
  • 1
    There was a typo in the `fmt=` line at the top of the script which I have now fixed; the second `%` was replaced with a `$`. Haven't been able to find my glasses for a few days, sorry for the confusion. Not sure what's happening regarding this being sequential; the pathname expansion on the `for` line, `*.png`, should match files in alphabetical/numeric order. Try again with the repaired `fmt` line and see if the results are as you expect. – ghoti Oct 12 '15 at 01:34
  • Thank you, that gave me the correct output I was looking for. Still seems to be spitting them out in order of the original unpadded order though. Is there a way to do the padding of the original numbers first, then in a separate command number them at the end sequentially? I am thinking if it does it two separate commands it will sort properly. Does that make sense? – VanCityGuy Oct 12 '15 at 02:28
  • 1
    Added some sorting options. Don't know what operating system you're running, so I included some that are portable. – ghoti Oct 12 '15 at 03:39
  • Thank you. I am using bash 4 in MacOSX but am hoping the script in portable to Linux. The second option you posted in your update worked for my purposes. Thank you so much for all your help! – VanCityGuy Oct 12 '15 at 04:35
1

To add sequential numbering at the end of filenames, you can use the following batch script

@echo off
setlocal EnableDelayedExpansion
set suffix=100
for /F "delims=" %%i IN ('dir /B *.txt') do (
    set /A suffix+=1
    ren "%%i" "%%~ni_!suffix!.txt"

Delayed expansion is enabled to obtain instantaneous values of suffix variable inside the loop.

%%~ni is used to obtain the filename without the extension. For more such options just use 'for/?'

Referenced from this StackOverflow Question

Vishnu Prasad
  • 73
  • 1
  • 9