How to pick only the latest files based on the timestamp?

I have a few log files which get generated on a daily basis..So, I need to pick only the ones which get generated for that particular day.

-rw-r--r-- 1 staff 510732676 Apr 7 22:01 test.log040711
-rwxrwxrwx 1 staff 2147482545 Apr 7 21:30 test.log.2
-rwxrwxrwx 1 staff 2147482581 Apr 7 19:26 test.log.1

There are 3 files generated on april 7....I need to get only those files(ALL 3 of them)

Please help

ls -lrt test.log* | awk '/Apr  7/{x=$9}END{print x}'

---------- Post updated at 07:49 PM ---------- Previous update was at 07:46 PM ----------

d="Apr  7"
ls -lrt test.log* | awk  -v V="$d" '$0~V{x=$9}END{print x}'

Use nawk instead of awk if on SunOS / Solaris plateform

Best add a : to the pattern so you do not get Apr 7 1971,

or script to touch marker files at midnight before and after, and find ... -newer marker1 ! -newer marker2 -type f

Of course, if they keep writing the files, they show up on two days. Better to create them with a start date in the name.

ls -lrt | awk '{print $6$7" "$9 }' | grep Apr7 | awk '{print $2}'
ls -lrt | awk '{print $6$7" "$9 }' | grep Apr7 | awk '{print $2}'

works perfect...Thanks :slight_smile:

But how do i make the date get generated dynamically...Since i want the latest files on a daily basis and avoid any manual intervention.

---------- Post updated 04-19-11 at 06:55 AM ---------- Previous update was 04-18-11 at 03:12 PM ----------

if you look at the code..lets say i incorporate the following logic:

ls -lrt | awk '{print $6$7" "$9 }' | grep Apr7 | awk '{print $2}'

It would fetch me the log files for a particular day, but i need to avoid this manual intervention where i need to enter the date ...So i need something which would pick the files daily automatically and mv it to some folder and from there i can take it forward...

Methods which process the output from "ls -la" are prone to spurious matches and problems with filenames containing space characters. None of the examples posted so far really work.

Another approach. Find all the files in the directory which were created after midnight. The filenames are available in the centre of the do-done loop if you need to do further processing.

YYYYMMDD="`date +%Y%m%d`"       # Reversed date yyyymmdd
REFERENCE=/var/tmp/reference.${YYYYMMDD}.$$
touch -t ${YYYYMMDD}0000 ${REFERENCE}
#
ls -1d * 2>/dev/null | while read FILENAME
do
     if [ -f "${FILENAME}" -a "${FILENAME}" -nt "${REFERENCE}" ]
     then
           echo "${FILENAME}"
     fi
done 
#
rm ${REFERENCE} 

There is a better method using just "find" but we don't know whether your directory has subdirectories.

Remember, find does not recurse for files, so glob in a find with only file names and use -newer. Usually, a glob of your files can be devised that does not pic up dirs, like '*.*'.

This will fetch all file(s) created on today.

ls -lrt | awk '{print $6$7" "$9 }' | grep `date +%b""%d` | awk '{print $2}'

---------- Post updated at 03:47 AM ---------- Previous update was at 03:41 AM ----------

make sure that month is Initcap

mon='Apr'
dd='25'
ls -lrt | awk '{print $6$7" "$9 }' | grep $mon $dd | awk '{print $2}'

Using find will output filenames only for all files modified not only within the last 24 hours, but all files modified today and from the beginning (midnight) of yesterday.

No need to 'touch' a file at a certain timestamp.

find . -maxdepth 1 -mindepth 1 -type f -mtime -1 -daystart | sort

NOTE: tested on GNU find.

Hi PalaniSVR, The code you provided is cool and serves my reqmt..But how do i get the result into a variable? please help

The problem with "find -mtime -1", even with -daystart, is that unless it starts on the first second each day, there can be gaps or duplications in the find. For precision, it is better to touch a marker file and find -newer $marker_file, using two markers as I described to bracket either N exact calendar days or one exact batch since last run.

Even then, a file being modified ongoing could be included in multiple days, in different versions, of course.

I happened to schedule the script and somewhat it back fired. Instead of picking those files which created on a particular day, it picked almost all the files..Please let me know how to handle this..

---------- Post updated at 07:21 AM ---------- Previous update was at 12:40 AM ----------

ls -lrt | awk '{print $6$7" "$9 }' | grep `date +%b""%d` | awk '{print $2}'

fetches only files for a particular day, but i need to get whatever files it pulls into a variable and copy those files to a different location(path)...Please help

I usually grep for 'MMM DD ..:' if I go that way, to avoid picking up prior years. The touch/-newer method does not suffer from ls formatting challenges.

Maybe you need to use nawk not awk?

Pickett, whatever are your ideas, can you pen them down...AM being a Novice here. Please let me know how do i take the result into a variable and copy the same over to an other location...below is what am expecting(i might be wrong but something in those lines)

new='ls -lrt | awk '{print $6$7" "$9 }' | grep `date +%b""%d` | awk '{print $2}''
echo $new
cp $new somelocation/path

This suggested command contains design and implementation errors. Consider what happens on April 1st. The grep match string becomes "Apr01" which will not match a directory list.

A less-than-perfect way of picking up files and directories created today is to match against the date and check that there is a colon character somewhere on the line.

TODAY="`date '+%b %e'`"        # Mmm d
ls -lar | grep "${TODAY}"|grep ":"

The importance here is to get the "date" command right and to preserve spaces in the date throughout by proper use of double quote characters.

Beware of dates with a single digit day. The command "date +%d" which is wrongly advised in various earlier posts gives the day of the month with a leading zero but "ls -lar" give the day of the month with a leading space. Therefore we must use "date +%e" and preserve that space character.
My example is not a recommended method (mainly because it does not work with filenames containing colon characters and is awkward with filenames containing space characters). My earlier post in this thread is a recommended method.

Dear experts,

Do you find find :smiley: with touch to be much more reliable in scripts ?

If you are referring to post #1 , yes. This is mainly because the format of "ls -la" changes for older files (the time gets replaced with the year).

There are more techniques available depending on exactly what Operating System and tools you have.
For the moment we'll assume that you don't let an open log run through midnight. This can make scripting "on a daily basis" difficult.

Methyl the code you provided picks the files created on a particular day ie today and lists them on the screen, but my question is, after you run this script, lets say i have 2 files created on the same day, How do i copy these 2 files to a different location..if this is answered then i believe i can close this discussion for good..Please help..Thanks

Well, you cannot hide ' inside ', and you have to do a 'command stdout to string' conversion $(...) or `...`. Think of echo as 'command line string to stdout' converter, and this is the opposite.

cp $(
 ls -lrt | awk '
   {print $6$7" "$9 }
  ' | grep `date +%b""%d` | awk '
   {print $2}
  ' ) somewhere/new

Now, if you dislike nesting:

 ls -lrt | awk '
   {print $6$7" "$9 }
  ' | grep `date +%b""%d` | awk '
   {print $2}
  ' | mv $( cat ) somewhere/new

Both of these are ugly if no files, so sometimes, put the list in an env. var.:

new=$(
 ls -lrt | awk '
   {print $6$7" "$9 }
  ' | grep `date +%b""%d` | awk '
   {print $2}
  '
 )
 
if [ "$new" != "" ]
then
 mv $new somewhere/new
fi

If the number of files is really big, like from a long find, then waiting for a complete list is an unconscionable delay, so you want to pipeline parallel more:

ls -lrt | awk '
   {print $6$7" "$9 }
  ' | grep `date +%b""%d` | awk '
   {print $2}
  ' | while read f
 do
  mv $f somewhere/new
 done

but this lacks economy of scale on mv calls (nice for must-do-one-at-a-time commands), so use xargs to batch them up:

ls -lrt | awk '
   {print $6$7" "$9 }
  ' | grep `date +%b""%d` | awk '
   {print $2}
  ' | xargs -n101 echo | while read fs
 do
  mv $fs somewhere/new
 done

xargs is 'pile args from this many stdin lines on the end of the supplied command and execute'. The number 101 is magic, in that you can argue that you got over 99% of any economy of scale while minimizing latency to first mv. Specifying the number to xargs with -n not only limits the delay to first mv, it also says no execute for 0 lines.

The grep pattern needs to be `date '+^%b''%d '` so it both matches the date only at beginning of line (^) not in the file name, and matches the space separator (May1 and not May19 ).

This is just about perfect. Awesome piece of work Pickett..Thanks a ton :)..You are the Man