As you've already discovered, putting our $i = 28; in the main script doesn't work because it resets $i to 28 for every filename - rename executes every statement in the main script once for every filename.
You can set an initial value for a variable (or run any other setup statementscode that only needs to be donerun once perwhen the script first executes) in a BEGIN block (e- e.g. BEGIN {our $i = 28};, which is only executed once when the script first executes.
You still have to declare the variable as a package global variable with our in both the BEGIN block and the main script because rename runs perl code in strict mode. See perldoc -f our and perldoc strict.
$ rename -n 'BEGIN {our $i = 28}; our $i; s/_.*/sprintf("_%03d.png", $i++)/e' *.png rename(abc_128390.png, abc_028.png) rename(abc_138493.png, abc_029.png) rename(abc_159084.png, abc_030.png)
This works too:
$ rename -n 'BEGIN {our $i = 28}; s/_.*/sprintf("_%03d.png", our $i++)/e' *.png
Note: you do not have to declare the variable with our every time you use the variable. Declare it only once in each code block, i.e. once in BEGIN and once in the main script - either beforebefore it is first used in a code block, or whenwhen it is first used in a block.
Also worth noting: if you need to use a variable that getsshould be reset for every filename, declare it as a local variable with my rather than our. See perldoc -f myperldoc -f my.
For a contrived example:
$ rename -n 'BEGIN {our $i = 28}; our $i; my $formatted_number = sprintf("_%03d.png", $i++); s/_.*/$formatted_number/' *.png rename(abc_128390.png, abc_028.png) rename(abc_138493.png, abc_029.png) rename(abc_159084.png, abc_030.png)
In this version, we don't need the /e modifier to the s/// operation because we don't need to evaluate the replacement as perl code, just use it as an interpolated variable. See perldoc -f s