1

Some GNU utils (e.g., mv and cp) can create numbered backups (foo.~1~). Others (e.g., wget) cannot. I would like to create numbered backups before running tools which overwrite files by default. Here is a bash function which appears to do what I need:

backup(){                       # back up the file, emacs style
  file=$1
  if test -f "${file}"; then
    /bin/mv --backup=numbered "$(mktemp ${file}XXX)" "${file}"
    /bin/rm "${file}"
  fi
}

to be used, e.g., like this:

backup foo
curl http://.... > foo

I wonder if there is a better way.

2
  • Apart from the fact that the script obviously breaks with files that contain whitespace in their path—which can be easily fixed though—why are you asking if there's anything "better"? Better in what aspect?
    – slhck
    Aug 20, 2013 at 20:58
  • 1
    @slhck: thanks for the bug catch - should be fixed. "better" - maybe I am missing something obvious and I do not need these 7 lines? maybe there is a trivial one-liner?
    – sds
    Aug 20, 2013 at 21:14

2 Answers 2

1

A small improvement over the OP's solution to make it more generally usefull:

  • Works with directories.
  • The mktemp argument might need quotes, too.
  • I'd && the commands in order not to get an error message from mv if mktemp fails, etc.
  • Added option / argument separators -- in case of filenames which start with a dash.
backup(){                       # back up the file, emacs style
  local file=$1
  local tmp
  if test -e "${file}"; then
    tmp=$(mktemp -- "${file}XXX") && /bin/mv --backup=numbered --no-target-dir -- "$tmp" "${file}" && /bin/rm -- "${file}"
  fi
}

BTW, cp supports making a numbered backup with source == target.

> cp -v --backup=t --force a a
'a' -> 'a.~4~'
0

Still not exactly a one liner, but you get closer with one single call to perl together with its powerful e option (ie. execute the substitution part):

backup(){
    mv "$1" "$(echo $1 |perl -pe '~s|(.*?)(~([0-9]*)~)?$|print "$1~".(${3}+1)."~"|e and exit')"
}

Notice the and exit what prevents perl to print the matching count that otherwise pollutes the name.

You may also want to add 2>/dev/null to the end of the line to keep it quiet when the file does not exist.

1
  • This is more complex than my solution; it does not use the --backup option of mv, it emulates it with perl.
    – sds
    Aug 21, 2013 at 13:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .