Adding sequential numbers to the end of file names - Shell Script Adding sequential numbers to the end of file names - Shell Script shell shell

Adding sequential numbers to the end of file names - Shell Script


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/shfmt="output.%04d.%04d.png"cd /${1-$PWD}n=1for 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 extglobls -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.


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

@echo offsetlocal EnableDelayedExpansionset suffix=100for /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