Find newest file in a unix directory

>> Saturday, 7 September 2019


Files and directories have a number of attributes.  

Modification time can be an issue when looking for the 'latest' directory.  I wrote a shell script that was creating new directories and also writing files into the latest directory depending on the switches past in.  I found if I started the two processes at exactly the same time.  The oldest directory was modified last, completely stuffing up my sort later looking for the newest directory. 

       find . -name "partname*" -maxdepth 1 -printf '%T@ %p\0' 2>/dev/null | sort -z -nr

           find           
                 -name         I only want certain files or directories
                 -maxdepth  1 only look at this level not recursively
                 -printf
                           %T modification time
                            @ seconds since Jan. 1, 1970, 00:00 GMT
                          %p file name
                           \0 the terminator rather than \n (newline) to avoid problems with strange filenames
                 
             2>/dev/null don't include errors in the output
              |  (pipe) then do the next command I give you
           
             sort
                -z     because I used \0 in the previous command don't look for a linefeed
                -n    sort numerically
                -r     put the largest number at the top

But modification time was an issue so I shifted to ctime - which is change time (not creation) 

        change time –ctime   %C 
        modify time –mtime %T
        (access time –atime    %A )

Change time is set on creation and alters when there is a chmod, chown or mv on the file.



      find . -name "partname*" -maxdepth 1 -printf '%C@ %p\0' 2>/dev/null | sort -z -nr


So in order to scrape off the latest file system name this completes in my scripts with:

       IFS= read -r -d $'\0' line < < (find . -name "partname*" -maxdepth 1 -printf '%C@ %p\0' 2>/dev/null | sort -z -nr )
       FullPathToNewestDirectory="${line#* }"

      IFS Internal Field Separator - make this the delimiter
      read
         -r                       backslash is not an escape character
        -d  $'\0'  line   take the entire input as one line (the space between the -d and $ is important)
      ${line#* }        the space after * matters here  ${parameter#word the pattern word will be removed from the beginning of the value of $parameter. It's called "Remove Smallest Prefix Pattern" because it will remove the shortest matching prefix string that matches the pattern in word (with ## in place of # it removes the longest matching prefix string).
      
< <                   Note the space between these two redirect symbols
                 
     
So now I have a variable that looks like
        /dir/dir/dir   (I'm looking for a list of directories, yours might be /dir/dir/file it's all the same)
and I only want the last part of this path

              echo $FullPathToNewestDirectory | awk -F/ '{ print $(NF ) }'

             echo show contents of the variable
              |  (pipe) then do the next command I give you
             awk
                  -F/  the fields separator is / (the lack of space between F and / is important)
                   '{ print $(NF ) }'    NF is number of fields of the current record, printing $NF means printing the last one.

I use NF because I'm not always sure server to server how many levels of directories I might have:

 
 IFS= read -r -d $'\0' line < < (find $BACKUPHOME -name "backupdir_partname*" -maxdepth 1 -printf '%C@ %p\0' 2>/dev/null | sort -z -nr )
FullPathToNewestDirectory="${line#* }"
ActualDirectory=`echo $FullPathToNewestDirectory | awk -F/ '{ print $(NF ) }'`

 If you plan to work with this in a script you need to consider that if there are no files or directories where you are looking you will end up with an empty (but set) variable, this might mess up anything coming later.  You need to be sure you handle that/ 

I found it important to test for 
            -z   ${FullPathToNewestDirectory:+x}

This tests that not only is the parameter set but also that it isn't null.

As I've been writing this I've been trying to recall what prevented me from using  ls to get where I needed to be.  I know It caught me out and why may come back to me.  If it does,  I will update again but why not see if it take you where you need to go first

ls -ABc 

0 comments:


  © Blogger template Simple n' Sweet by Ourblogtemplates.com 2009

Back to TOP