9

I want to list all files (sorted by date) that are newer than timestamp in format 20130207003851 in directory /tmp only. Subdirectories can be omitted.

Using SUSE Linux Enterprise Server 11.

The output format should be

S0002948.LOG Feb  7 03:28 
S0002935.LOG Feb  7 05:58 
S0002952.LOG Feb  7 09:58 
S0002940.LOG Feb  7 11:58 

find /tmp -newermt "7 feb 2013" -ls lists the files I want but

  • how can I use the timestamp in a format 20130207003851
  • how can I sort the output?
  • how can I display only file name and date. File name first and then the date?

ps I don't want to use touch to create reference file for find

pss

find -newermt "20130207003851" -ls
find: I cannot figure out how to interpret `20130207003851' as a date or time
2
  • What is 2013007000385 supposed to represent? I guess 2013 is the year, but how do you get from 007000385 to Feb 7? Feb 12, 2013 at 0:44
  • @Gilles: Supposed to be 20130207003851. Didn't copy it correctly or ... sorry for that.
    – Radek
    Feb 12, 2013 at 0:48

2 Answers 2

11

find supports a lot of date input formats. The simplest format to obtain is YYYYMMDD HH:MM:SS. You already have the digits in the right order, all you have to do is extract the first group (${timestamp%??????}: take all but the last 6 characters; ${timestamp#????????}: take all but the first 8 characters), and keep going, appending punctuation then the next group as you go along.

timestamp=20130207003851
timestring=${timestamp%??????}; timestamp=${timestamp#????????}
timestring="$timestring ${timestamp%????}"; timestamp=${timestamp#??}
timestring="$timestring:${timestamp%??}:${timestamp#??}"

In bash (and ksh and zsh), but not in ash, you can use the more readable ${STRING_VARIABLE:OFFSET:LENGTH} construct.

timestring="${timestamp:0:8} ${timestamp:8:2}:${timestamp:10:2}:${timestamp:12:2}"

To sort files by date, print out the file names preceded by the dates and sort that, then strip the date prefix. Use -printf to control the output format. %TX prints a part of the modification time determined by X; if X is @, you get the number of seconds since the Unix epoch. Below I print three tab-separated columns: the time in sortable format, the file name, and the time in human-readable format; cut -f 2- removes the first column and the call to expand replaces the tab by enough spaces to accommodate all expected file names (adjust 40 as desired). This code assumes you have no newlines or tabs in file names.

find -maxdepth 1 -type f \
     -newermt "$timestring" -printf '%T@\t%f\t%Tb %Td %TH:%TM\n' |
sort -k1n |
cut -f 2- |
expand -t 40
6
  • only the find part find -newermt "$timestring" -printf '%M@\t%f %Mb %Md %MH:%MM\n' gives me funny output -rwxrwxrwx@ S0002975.LOG -rwxrwxrwxb -rwxrwxrwxd -rwxrwxrwxH:-rwxrwxrwxM
    – Radek
    Feb 12, 2013 at 1:25
  • @Radek Sorry, it's %T for the mtime, %M is the permissions. Feb 12, 2013 at 1:29
  • Beautiful. Works smoothly. My final code is find /tmp -maxdepth 1 -type f -newermt "20130207 00:38:51" -printf '%T@\t%f-%Tb %Td %TH:%TM\n' | sort -k1n | cut -f 2- I separated file name and time by - because I will capture the output in php and use - as separator. Thank you so much.
    – Radek
    Feb 12, 2013 at 1:37
  • @Gilles it's awesome, but if you explain timestring , it will help more.. Feb 12, 2013 at 3:37
  • @RahulPatil Done. I also added a more readable bash method. Feb 12, 2013 at 10:32
5

With zsh:

zmodload zsh/stat
newer() {
  local t
  zstat -A t -F %Y%m%d%H%M%S +mtime -- $REPLY && (( t >= timestamp ))
}
timestamp=20130207003851
print -rl -- /tmp/*(D.Om+newer)

The newer function returns true for files newer than $timestamp (note that zsh's zstat doesn't support subsecond accuracy though).

Then all we do is use zsh globbing qualifiers: D to include dot files, . to only consider regular files, Om to order on modification time, and +newer to call the newer function to determine which file to select.

If you want to display the file timestamps as well, you can change newer to:

newer() {
  local t
  zstat -A t -F %Y%m%d%H%M%S +mtime -- $REPLY &&
    REPLY+=$'\t'$t &&
    (( t >= timestamp ))
}

Note though that the result of the filename generation will include the timestamps which means you can't use those as filenames any more.

1
  • this won't work over ssh, for instance.
    – evandrix
    Jan 26, 2016 at 15:33

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.