2

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
13
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. – John Magnolia Mar 3 '12 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. – SimonJGreen Mar 3 '12 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. – SimonJGreen Mar 3 '12 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 – davey Mar 3 '12 at 15:22
7
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 = malloc(newneeded);
        oldpath = 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);
            free(newpath);          
            free(oldpath);          
            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",res);
                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. – Gerald Schneider Jan 5 '18 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 '18 at 9:36
1
cp foo.txt{,`date +%Y.%m.%d.%H.%M.%S`}
1
  • 2
    Why does every one hate $()? – Aaron Copley May 20 '14 at 19:22
0
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

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.