Batch rename files to a sequential numbering
Solution 1
I can't think of a solution that handles incrementing the counter in a more clever way, but this should work:
i=0
for fi in abc_??????.png; do
mv "$fi" abc_$i.png
i=$((i+1))
done
It should be safe to use abc_*.png
because it is expanded before the first mv
is ever executed, but it can be useful to be very specific in that you only want files with a six-character timestamp at the end.
Solution 2
With rename
utility as part of Perl packages, you would do:
rename -n 'our $i; s/_.*/sprintf("_%03d.png", $i++)/e' *.png
Note: -n
is for dry run, remove it to rename apply on files.
Solution 3
With zsh
:
typeset -A count
incr='++count[$1/$2]'
(zmv -n '([^0-9]##)<->(*)(#qn)' '$1${(l:3::0:)$((incr))}$2')
Remove the -n
when happy.
(note the extra step using the incr
variable to avoid the ACE vulnerability)
Example:
$ ls
a1b.png abc_128390.png abc_159084.png x12y.png
a2b.png abc_138493.png a.png x2y.png
$ typeset -A count
$ incr='++count[$1/$2]'
$ (zmv -n '([^0-9]##)<->(*)(#qn)' '$1${(l:3::0:)$((incr))}$2')
mv -- a1b.png a001b.png
mv -- a2b.png a002b.png
mv -- abc_128390.png abc_001.png
mv -- abc_138493.png abc_002.png
mv -- abc_159084.png abc_003.png
mv -- x2y.png x001y.png
mv -- x12y.png x002y.png
Solution 4
Avoid overwriting existing files:
i=1
for fi in abc_??????.png; do
a="abc_$(printf '%04d' "$i").png"
if [[ -e $a ]]; then
echo "file $a exist, not moving $fi"
else
mv "$fi" "$a"
fi
i=$((i+1))
done
Solution 5
you can use cut to cut out parts of the filename, for example, if you want to rename files like
"1 first.jpg"
"2 second.jpg"
...
to
"10 first.jpg"
"20 second.jpg"
...
you can use
for i in *jpg; do
mv -iv "$i" "$(echo "$i"|cut -d\ -f1)0 $(echo "$i"|cut -d\ -f2-99)";
done
![NicApicella](https://i.stack.imgur.com/8ScDo.jpg?s=256&g=1)
NicApicella
Updated on September 18, 2022Comments
-
NicApicella almost 2 years
I am trying to batch-rename a bunch of files in my shell, and even though there is plenty of material about it on the internet, I cannot seem to find a solution for my specific case.
I have a bunch of files that have (what appears to be) a "timestamp-id":
abc_128390.png abc_138493.png abc_159084.png ...
that I'd like to exchange for a counter:
abc_001.png abc_002.png abc_003.png ...
My (plenty) naïve approach would be something like:
mv abc_*.png abc_{001..123}.png
Also, I could not figure out a way to make it work with a
for
-loop.FWIW, unfortunately
rename
is not available on this particular system.Any advice would be greatly appreciated!
-
ilkkachu over 6 yearsFWIW:
abc_*.png abc_{001..123}.png
expands to the existing file names, and then the generated names in sequence, andmv
has no way to determine what the distinction between them is. (Try e.g.echo abc_*.png abc_{001..123}.png
)
-
-
ilkkachu over 6 yearsChange the destination file name to
"$(printf "abc_%03d.png" "$i")"
to get the zero-padding, too -
NicApicella over 6 yearsI had been very close to this solution at one point… The zero-padding is the cherry on top! Thanks1
-
teracow over 4 yearsMinor point: the line that increments $i can be reduced to just
((i++))
-
Merlin over 4 yearsi like this approach, but I think your delimiter choice is causing the whole filename to be appended. Maybe use the
-c1
and-c2-99
flags for character instead of field? Prob-c2-
would capture to end of line.