4

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!

An Dorfer
  • 1,178
  • 2
  • 8
  • 14
André
  • 43
  • 1
  • 3

2 Answers2

5

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.

Lesmana
  • 19,803
  • 6
  • 45
  • 44
  • 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 01:20
  • What is `rotatemap.state`? – gies0r Jul 08 '19 at 21:23
0
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
        n=${file##*-}
        n=${n%.*}
        echo mv "$file" "$dest_dir/${dest_prefix}-$((n+1)).$dest_ext"
    done
}

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
glenn jackman
  • 25,463
  • 6
  • 46
  • 69
  • 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 01:13
  • Here's 2 lines for 9 files. – glenn jackman Apr 26 '14 at 01: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](http://www.gnu.org/software/bash/manual/bashref.html#Command-Substitution); the latter is [arithmetic evaluation](http://www.gnu.org/software/bash/manual/bashref.html#Arithmetic-Expansion). – glenn jackman Apr 26 '14 at 22:06