MohammedAli_
MohammedAli_

Reputation: 175

Unix If file exists, rename

I am working on a UNIX task where i want check if a particular log file is present in the directory or not. If it is present, i would like to rename it by appending a timestamp at the end. The format of the file name is as such: ServiceFileName_0.log

This is what i have so far but it wouldn't rename when i run the script, even though there is a file with the name ServiceFileName_0.log present.

renameLogs()
{
   #If a ServiceFileName log exists, rename it

   if [ -f $MY_DIR/logs/ServiceFileName_0.log ]; 
   then
    mv ServiceFileName_0.log ServiceFileName_0.log.%M%H%S
   fi
}

Pls Help!

Thanks

Upvotes: 0

Views: 10966

Answers (4)

zwol
zwol

Reputation: 140748

This isn't your apparent immediate problem, but the if construct is wrong: it introduces a time-of-check to time-of-use race condition. In between the if [ -f check and the mv, some other process could come along and change things so you can't move the file anymore even though the check succeeded.

To avoid this class of bugs, always write code that starts by attempting the operation you want to do, then if it failed, figure out why. In this case, what you want is to do nothing if the source file didn't exist, but report an error if the operation failed for any other reason. There is no good way to do that in portable shell, you need something that lets you inspect errno. I'd probably write this C helper:

#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(int argc, char **argv)
{
    if (argc != 3) {
        fprintf(stderr, "usage: %s source destination\n", argv[0]);
        return 2;
    }
    if (rename(argv[1], argv[2]) && errno != ENOENT) {
        fprintf(stderr, "rename '%s' to '%s': %s\n", 
                argv[1], argv[2], strerror(errno));
        return 1;
    }
    return 0;
}

and then use it like so:

renameLogs()
{
    ( cd "$MY_DIR/logs"
      rename_if_exists ServiceFileName_0.log ServiceFileName_0.log.$(date +%M%H%S)
    )
}

The ( cd construct fixes your immediate problem, and unlike the other suggestions, avoids another race in which some other process comes along and messes with the logs directory or its parent directories.

Obligatory shell scripting addendum: Always enclose variable expansions in double quotes, except in the rare cases where you want the expansion to be subject to word splitting.

Upvotes: 0

Jonathan Leffler
Jonathan Leffler

Reputation: 754450

renameLogs()
{
    if [ -f $MY_DIR/logs/ServiceFileName_0.log ] 
    then mv $MY_DIR/ServiceFileName_0.log $MY_DIR/ServiceFileName_0.log.$(date +%M%H%S)
    fi
}

Use the directory prefix consistently. Also you need to specify the time properly, as shown.

Better, though (less repetition):

renameLogs()
{
    logfile="$MY_DIR/logs/ServiceFileName_0.log"
    if [ -f "$logfile" ] 
    then mv "$logfile" "$logfile.$(date +%H%M%S)"
    fi
}

NB: I've reordered the format from MMHHSS to the more conventional HHMMSS order. If you work with date components too, you should seriously consider using the ordering recommended by ISO 8601, which is [YYYY]mmdd. It groups all the log files for a month together in an ls listing, which is usually helpful. Using ddmm order means that the files for the first of each month are grouped together, then the files for the second of each month, etc. This is usually less desirable.

Upvotes: 3

rahmu
rahmu

Reputation: 5878

You could replace this:

mv ServiceFileName_0.log ServiceFileName_0.log.%M%H%S

with this

mv $MY_DIR/logs/ServiceFileName_0.log $MY_DIR/logs/ServiceFileName_0.log.%M%H%S

Upvotes: 0

cnicutar
cnicutar

Reputation: 182664

You might need to prefix the file name with the $MY_DIR path, just like you did in the test.

Upvotes: 3

Related Questions