I have a couple of files, let's say map-0.jpg (newest), map-1.jpg, map-2.jpg, ..., map-9.jpg (oldest). Now my cronjob downloads a new picture from the internet and should save it as map-0.jpg. All other files, however, should be newly enumerated (0 -> 1, 1 -> 2, and so on). Number 9, in my case, can be discarded.

Is there a handy bash-command that enumerates my files similar as logrotate does?

Thanks for help!


you can use logrotate with some restrictions.

create a rotatemap.conf:

/path/to/map.jpg {
  rotate 9

then run logrotate from your cronjob like this:

logrotate -f -s /path.to/rotatemap.state /path/to/rotatemap.conf

this will rename the file map.jpg to map.jpg.1 and will delete the old map.jpg.9 if it exists.

the restrictions:

  • just about every path has to be hardcoded.
  • the number in the rotated files are always at the end of the filename. at least i found no way to change this.

read the fine manual of logrotate (man logrotate) for more information.

  • 1
    Thank you, I think I will do it that way. The hardcoding thing is okay, as I have to use the full path in my cronjob-table (crontab -e) anyway. The rotated files will be served by Apache, which I can convince to add the appropiate Content-type-header! – André Apr 26 '14 at 1:20
myrotate() {
    # usage: myrotate /path/to/map-0.jpg
    local dest=$1
    local dest_dir=$(dirname "$dest")
    local dest_prefix=$(basename "${dest%-*}")
    local dest_ext=${dest##*.}
    local n

    printf "%s\n" "$dest_dir/${dest_prefix}"-*."$dest_ext" | 
    sort -V -r | 
    while IFS= read -r file; do
        echo mv "$file" "$dest_dir/${dest_prefix}-$((n+1)).$dest_ext"

Change "echo mv" to "mv" if you're satisfied it's working.

I missed the bit where you only want to keep 9. Here's some terse bash:

for i in {8..0}; do mv map-$i.jpg map-$((i+1)).jpg; done
mv $file map-0.jpg
  • Thank you very much for your answer! I solved this by using 8x mv-commands (mv 1.jpg 0.jpg, mv 2.jpg 1.jpg) in my Bash-cronjob-script. This is very simple and uses 8 lines for 9 files (renaming 8 and discarding 1 files). Well, I thought there would be a more elegant way. However, I will study your script; maybe it inspires me in the future, when I will have similar problems :) – André Apr 26 '14 at 1:13
  • Here's 2 lines for 9 files. – glenn jackman Apr 26 '14 at 1:31
  • Well, that's a nice one-/two-liner that I expected ^^ – André Apr 26 '14 at 17:26
  • It doesn't matter if I keep 9, 10 or 20 files... The most interesting part is the $((i+1)) thing for me. I know that $() is a sub-command. So (i+1) will be calculated, but why don't you use "echo"? Or is the bash intelligent enough to know what I want? And I think you forgot the dollar-sign in the subcommand, didn't you? :) – André Apr 26 '14 at 17:32
  • $( ... ) and $(( ... )) are two separate syntaxes in bash. The former is command substitution; the latter is arithmetic evaluation. – glenn jackman Apr 26 '14 at 22:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.