75

I need to make a backup of a file, and I would like to have a timestamp as part of the name to make it easier to differentiate.

How would you inject the current date into a copy command?

[root@mongo-test3 ~]# cp foo.txt {,.backup.`date`}
cp: target `2013}' is not a directory

[root@mongo-test3 ~]# cp foo.txt {,.backup. $((date)) }
cp: target `}' is not a directory  

[root@mongo-test3 ~]# cp foo.txt foo.backup.`date`
cp: target `2013' is not a directory
116

This isn't working because the command date returns a string with spaces in it.

$ date
Wed Oct 16 19:20:51 EDT 2013

If you truly want filenames like that you'll need to wrap that string in quotes.

$ touch "foo.backup.$(date)"

$ ll foo*
-rw-rw-r-- 1 saml saml 0 Oct 16 19:22 foo.backup.Wed Oct 16 19:22:29 EDT 2013

You're probably thinking of a different string to be appended would be my guess though. I usually use something like this:

$ touch "foo.backup.$(date +%F_%R)"
$ ll foo*
-rw-rw-r-- 1 saml saml 0 Oct 16 19:25 foo.backup.2013-10-16_19:25

See the man page for date for more formatting codes around the output for the date & time.

Additional formats

If you want to take full control if you consult the man page you can do things like this:

$ date +"%Y%m%d"
20131016

$ date +"%Y-%m-%d"
2013-10-16

$ date +"%Y%m%d_%H%M%S"
20131016_193655

NOTE: You can use date -I or date --iso-8601 which will produce identical output to date +"%Y-%m-%d. This switch also has the ability to take an argument to indicate various time formats:

$ date -I=?
date: invalid argument ‘=?’ for ‘--iso-8601’
Valid arguments are:
  - ‘hours’
  - ‘minutes’
  - ‘date’
  - ‘seconds’
  - ‘ns’
Try 'date --help' for more information.

Examples:

$ date -Ihours
2019-10-25T01+0000

$ date -Iminutes
2019-10-25T01:21+0000

$ date -Iseconds
2019-10-25T01:21:33+0000
| improve this answer | |
  • 1
    +1 - I always use a format specifier for the date, either "%Y%m%d-%H%M%S" or "%y%m%d-%H%M%S". – ChuckCottrill Oct 17 '13 at 1:12
  • Just touch foo`date +%F` also works fine. – Vadzim Dec 23 '14 at 14:28
  • caveat: This does not work in csh shell – Govi S Jan 24 '19 at 8:47
  • 1
    @GovindaSakhare - csh/tcsh switch the subshell notation to backticks (...) instead of $(..). C shells apparently don't support that notation for subshells. – slm Jan 24 '19 at 13:28
  • date +"%Y-%m-%d" is the same as date -I. I wold recomment the iso formats anyway. The precision can be specified by adding hours, minutes, seconds, or ns to the parameter -I. Example date -Iseconds. – Till Schäfer Oct 24 '19 at 15:43
13
cp foo.txt {,.backup.`date`}

This expands to something like cp foo.txt .backup.Thu Oct 17 01:02:03 GMT 2013. The space before the braces starts a new word.

cp foo.txt {,.backup. $((date)) }

The braces are in separate words, so they are interpreted literally. Furthermore, $((…)) is the syntax for arithmetic expansion; the output of date is nothing like an arithmetic expression. Command substitution uses a single set of parentheses: $(date).

cp foo.txt foo.backup.`date`

Closer. You could have expressed this with braces as cp foo.{txt,.backup.`date`}. There is still the problem that the output of date contains spaces, so it needs to be put inside double quotes. This would work:

cp foo.{txt,backup."`date`"}

or

cp foo.{txt,backup."$(date)"}

The default output format of date is not well-suited to a file name, and it might even not work if a locale uses / characters in the default output format. Use a Y-M-D date format so that the lexicographic order on file names is the chronological order (and also to avoid ambiguity between US and international date formats).

cp foo.{txt,backup."$(date +%Y%m%d-%H%M%S)"}
| improve this answer | |
  • last one gave me cp: target `foo..backup.20160913-134158' is not a directory – Kalpesh Soni Sep 13 '16 at 17:42
  • @KalpeshSoni The exact command I posted can't produce this error message. You must have used a different command. – Gilles 'SO- stop being evil' Sep 13 '16 at 17:45
11

If you really want to use the verbose date, you should protect the backtick. The with this date format is that it has embedded spaces, a no-no in a Unix shell unless you put them inside quotes (or escape them some other way).

cp foo.txt "foo-`date`.txt"

However, I prefer to use the shorter ISO format:

cp foo.txt foo-`date --iso`.txt
| improve this answer | |
5

Use a function, it will make your life easier. This is what I use:

backup () { 
    for file in "$@"; do
        local new=${file}.$(date '+%Y%m%d')
        while [[ -f $new ]]; do
            new+="~";
        done;
        printf "copying '%s' to '%s'\n" "$file" "$new";
        \cp -ip "$file" "$new";
    done
}
| improve this answer | |
4

As date has by default whitespaces in its output, your last command failed. If you had quoted the last argument inside with ", it should work. Your other tries have just wrong syntax

Here a possible solution without whitespaces:

cp foo.txt foo.backup.$(date --iso-8601=seconds)  

or

cp foo.txt foo.backup.`date --iso-8601=seconds`

If you add

bk() {
     cp -a "$1" "${1}_$(date --iso-8601=seconds)"
}

to your .bashrc and re-login/let your bash reread it, you need just to call bk file.txt.

| improve this answer | |
3

You copy file to backup file whose name is created with appended time stamp

cp foo.txt backup_`date +"%d-%m-%Y"`.txt

OR:

You can display content of file using "cat" and redirect output to backup file whose name is created with appended time stamp

cat foo.txt > backup_`date +"%d-%m-%Y"`.txt

You can also use more FORMAT controls options as per your need Eg: %H , %M , %S ,etc.

| improve this answer | |
  • What's the advantage of cat with redirection over cp? – Guido Apr 26 '16 at 13:29
  • It is just alternate way to do so – Atul Rokade Apr 26 '16 at 13:34
2

When I have to make a backup of a file I usually just do it this way.

cp foo.txt foo.backup.$(date +%F).txt

ls -l

foo.txt foo.backup.2017-9-19.txt

| improve this answer | |
  • 1
    This adds nothing that other answers have not already brought up. Additionally, the %F date format produces 2-digit months, and ls -l usually gives a tiny bit more info than just filenames. – Kusalananda Sep 19 '17 at 17:27
1

In bash you could type:

cp /path/to/long/filename !#$_$(date +Is)

Which expands to:

cp /path/to/long/filename /path/to/long/filename_$(date +Is)

Resulting in:

$ ls /path/to/long/filename*
filename  filename_2017-05-10T11:50:10+0300

The beef being date -Is. I like using it because it's easy to remember, type, and allows short versions (like -In if you are precision freak).


! starts an event designator:

 !#     The entire command line typed so far.

And $ is a word designator:

   $      The last word.  This is usually the last argument, but will expand to the zeroth word if there is only one word in the line.
| improve this answer | |
0

If you just want a backup of the file or directory then why type out the destination as well, just use the shell expansion to add the date to the end of the copy filename.

i.e

cp filename.sh{,."`date`"}

which results in

filename.sh.Sun 29 Sep 00:44:43 BST 2019

or simply use

cp filename{,.20190929}

filename.sh.20190929

Append the date to suite your needs. :)

| improve this answer | |

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