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 likeFILE-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