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!
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.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
.