4

Is it possible to run a cp command which creates a backup of a file and renames it with todays date/time

e.g:

  • foo.txt
  • foo.txt.2012.03.03.12.04.06

5 Answers 5

15
cp -p foo.txt foo.txt.`date +%Y.%m.%d.%H.%M.%S`
4
  • Is there a shorter way to write the date part? I am not bothered how the date is formatted. Mar 3, 2012 at 13:08
  • This. For elaboration, the backtick () is used in BASH to execute the command within the backticks and echo the response in line. For example, run "echo foo.txt.date +%Y.%m.%d.%H.%M.%S`" to see the response. Mar 3, 2012 at 13:09
  • 4
    Shortest way that is still useful would be date +%s. That will output unix timestamp which will allow you to order by date easily. Mar 3, 2012 at 13:10
  • 1
    The manual page which describes all the % values is strftime %F will give you an ISO8601 date: 2012-01-31 so you can dispense with the %Y%M%D part. You specify dots (.) above as separators. Unless these are absolutely necessary then I'd use the dashes. See en.wikipedia.org/wiki/ISO_8601
    – gm3dmo
    Mar 3, 2012 at 15:22
9
cp -p foo.txt foo.txt.`date -I`

this puts a date in the ISO format yyyy-mm-dd

2

Copy the below code snippet to mkcp.c and compile with

  • # gcc -o mkcp mkcp.c on linux or
  • # cl mkcp.c on Windows®.

# ./mkcp mkcp.c then runs a cp command and creates a copy such as mkcp.c_sav_2018-01-04.

#ifdef __linux__ 
#include<dirent.h>
#endif
#include<errno.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/stat.h> // mkdir
#include<sys/types.h>
#include<time.h>
#ifdef __linux__ 
#include<unistd.h>
#endif
#if defined(_MSC_VER)
#include<BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif

#if defined(__TINYC__)
#include "./dirent.h"

typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */

struct DIR
{
    handle_type         handle; /* -1 for failed rewind */
    struct _finddata_t  info;
    struct dirent       result; /* d_name null iff first time */
    char                *name;  /* null-terminated char string */
};

DIR *opendir(const char *name) {
    DIR *dir = 0;

    if(name && name[0])
    {
    size_t base_length = strlen(name);
    const char *all = /* search pattern must end with suitable wildcard */
    strchr("/\\", name[base_length - 1]) ? "*" : "/*";

    if((dir = (DIR *) malloc(sizeof *dir)) != 0 &&
       (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0)
    {
    strcat(strcpy(dir->name, name), all);

    if((dir->handle =
    (handle_type) _findfirst(dir->name, &dir->info)) != -1)
    {
    dir->result.d_name = 0;
    }
    else /* rollback */
    {
    free(dir->name);
    free(dir);
    dir = 0;
    }
    }
    else /* rollback */
    {
    free(dir);
    dir   = 0;
    errno = ENOMEM;
    }
    }
    else
    {
    errno = EINVAL;
    }

    return dir;
}

int closedir(DIR *dir)
{
    int result = -1;

    if(dir)
    {
    if(dir->handle != -1)
    {
    result = _findclose(dir->handle);
    }

    free(dir->name);
    free(dir);
    }

    if(result == -1) /* map all errors to EBADF */
    {
    errno = EBADF;
    }

    return result;
}

struct dirent *readdir(DIR *dir)
{
    struct dirent *result = 0;

    if(dir && dir->handle != -1)
    {
    if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
    {
    result         = &dir->result;
    result->d_name = dir->info.name;
    }
    }
    else
    {
    errno = EBADF;
    }

    return result;
}

#endif

int cp(const char *from, const char *to) {
    int fd_to, fd_from;
    char buf[4096];

    ssize_t nread;
    int saved_errno;

    fd_from = open(from, O_RDONLY);
    if (fd_from < 0) {
    fprintf(stderr,"Error opening input file %s.\n", from);        
    return -1;
    }

    fd_to = open(to, O_WRONLY | O_CREAT | O_EXCL, 0666);
    if (fd_to < 0) {
    fprintf(stderr,"Error opening output file %s.\n", to);
    fprintf(stderr,"Most probably an output file %s exists already.\n", to);
    goto out_error;
    }

    while (nread = read(fd_from, buf, sizeof buf), nread > 0) {
    char *out_ptr = buf;
    ssize_t nwritten;

    do {
    nwritten = write(fd_to, out_ptr, nread);

    if (nwritten >= 0) {
        nread -= nwritten;
        out_ptr += nwritten;
    } else if (errno != EINTR) {
        goto out_error;
    }
    } while (nread > 0);
    }

    if (nread == 0) {
    if (close(fd_to) < 0) {
    fd_to = -1;
    goto out_error;
    }
    close(fd_from);

    /* Success! */
    return 0;
    }

  out_error:
    saved_errno = errno;

    close(fd_from);
    if (fd_to >= 0) close(fd_to);

    errno = saved_errno;
    return -1;
}

mode_t getumask() {
    mode_t mask = umask(0);
    umask (mask);
    return mask;
}

void help(char *this_program) {
    printf("usage:  %s [options] fts\n", this_program);
    printf("options:\n");
    printf("-h,--help       Show this help.\n");
    printf("fts             File or folder to save.\n");
}

void rmkdr(const char *dr) {
    #ifdef __linux__ 
    if (mkdir(dr,0777-getumask()) == -1) {
    // perror(argv[0]);
    fprintf(stderr,"Failed to create the folder %s.\n", dr);
    fprintf(stderr,"Most likely a folder %s exists already.\n", dr);
    fprintf(stderr,"Stop.\n");
    exit(EXIT_FAILURE);
    }
    #endif
    #if defined(__TINYC__)
    if (mkdir(dr) == -1) {
    // perror(argv[0]);
    fprintf(stderr,"Failed to create the folder %s.\n", dr);
    fprintf(stderr,"Most likely a folder %s exists already.\n", dr);
    fprintf(stderr,"Stop.\n");
    exit(EXIT_FAILURE);
    }
    #endif
}

int lmdir(const char *dr, char *ndr) {
    char *oldpath;
    char *newpath;
    DIR *dir;
    int res;
    size_t newneeded, oldneeded;
    struct dirent *entry;

    if(!(dir = opendir(dr))) {
    fprintf(stderr, "Argument is not a folder.\n");
    fprintf(stderr,"Stop.\n");
    exit(EXIT_FAILURE);
    }

    while((entry = readdir(dir)) != NULL) {
    #ifdef __linux__
    newneeded = snprintf(NULL, 0, "%s/%s", ndr,entry->d_name) + 1;      
    oldneeded = snprintf(NULL, 0, "%s/%s", dr,entry->d_name) + 1;
    newpath = (char *) malloc(newneeded);
    oldpath = (char *) malloc(oldneeded);
    snprintf(newpath, newneeded, "%s/%s",ndr,entry->d_name);
    snprintf(oldpath, oldneeded, "%s/%s",dr,entry->d_name);
    if(entry->d_type == DT_DIR) {
        if(strcmp(entry->d_name,".") == 0 || strcmp(entry->d_name,"..") == 0) continue;
        rmkdr(newpath);
        lmdir(oldpath, newpath);
    } else if(entry->d_type == DT_REG) {
        res=cp(oldpath,newpath);    
        if(res!=0) {
            exit(EXIT_FAILURE);
        }

    }       
    #endif
    #if defined(__TINYC__)
    newneeded = snprintf(NULL, 0, "%s/%s", ndr,entry->d_name) + 1;      
    oldneeded = snprintf(NULL, 0, "%s/%s", dr,entry->d_name) + 1;
    newpath = malloc(newneeded);
    oldpath = malloc(oldneeded);
    snprintf(newpath, newneeded, "%s/%s",ndr,entry->d_name);
    snprintf(oldpath, oldneeded, "%s/%s",dr,entry->d_name);
    if(opendir(oldpath) != NULL) {
        if(strcmp(entry->d_name,".") == 0 || strcmp(entry->d_name,"..") == 0) continue;
        rmkdr(newpath);
        lmdir(oldpath, newpath);
    } else {
        res=cp(oldpath,newpath);    
        if(res!=0) {
            fprintf(stderr, "Exit failure.\n");
            free(newpath);          
        free(oldpath);   
            exit(EXIT_FAILURE);
        }
    }
    #endif
    free(newpath);          
    free(oldpath);        
    }
}

int main(int argc, char *argv[]) {
char *cpstr;
char *drstr;
char *dtstr;
DIR *dir;
int i, res=0;
time_t t = time(NULL);

struct dirent *dptr;
struct tm tml;
tml = *localtime(&t);

for(i=0; i<argc; i++) {
    if(strcmp(argv[i],"--help")==0||strcmp(argv[i],"-h")==0) {
    help(argv[0]);
    return(0);
    }

}

if(argc<2) {
    help(argv[0]);
    return(1);
}

if(argv[1][strlen(argv[1])-1]=='/') {
    drstr=(char *) malloc((strlen(argv[1]))*sizeof(char));
    snprintf(drstr,strlen(argv[1]),"%s",argv[1]);
} else {
    drstr=(char *) malloc(1+strlen(argv[1])*sizeof(char));
    snprintf(drstr,1+strlen(argv[1]),"%s",argv[1]);
}

dtstr = (char *) malloc(12*sizeof(char));
snprintf(dtstr, 11, "%d-%02d-%02d", tml.tm_year + 1900, tml.tm_mon + 1, tml.tm_mday);

cpstr = (char *) malloc((1+strlen(dtstr)+strlen(drstr)+strlen("_sav_"))*sizeof(char));
strcpy(cpstr, drstr);
strcat(cpstr, "_sav_");
strcat(cpstr, dtstr);

if(!(dir = opendir(argv[1]))) {
    res=cp(argv[1],cpstr);
    if(res!=0) {
    fprintf(stderr,"Stop.\n");
    exit(EXIT_FAILURE);
    }
    fprintf(stdout, "Output to be written to: %s.\n", cpstr);
    fprintf(stdout, "Success.\n");
    free(cpstr);
    free(drstr);
    free(dtstr);
    exit(EXIT_SUCCESS);
}

rmkdr(cpstr);
lmdir(drstr, cpstr);

if(res==0) {
    printf("Output to be written to: %s.\n", cpstr);
    printf("Success.\n");
}
free(cpstr);
free(drstr);
free(dtstr);
return(0);
}

Note: mkcp actually checks whether the file to be written exists already. mkcp will stop in that case. Accordingly, any risk of data loss is minimized.

2
  • uhm ... you can just type mkcp() { cp "$1" "$1.`date +%Y-%m-%d`"; } in the shell and have the same result. add it to .bashrc for persistance. Jan 5, 2018 at 14:44
  • Thank you Gerald. Actually, my code is intended to work on windows as well as on linux. That is why I prefer a solution in c to a solution in bash script.
    – dzmanto
    Feb 9, 2018 at 9:36
1
cp foo.txt{,`date +%Y.%m.%d.%H.%M.%S`}
1
  • 3
    Why does every one hate $()? May 20, 2014 at 19:22
1
cp foo{,$(date -I)}

And if what you really want is a quick edit using sed, use something like sed -i.$(date -I) -e ...

Output format for date -I is like 2018-12-31

Cheers, Cameron

You must log in to answer this question.

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