0

How can I find a last updated file with the specific prefix in bash?

For example, I have three files, and I just want to see a file that has "ABC" and where the last Last_updatedDateTime desc.

fileName Last_UpdatedDateTime

abc123   7/8/2020 10:34am 
abc456   7/6/2020 10:34am 
def123   7/8/2020 10:34am
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
  • Note that it's case sensitive so `ABC` will not match any of those files. – Ted Lyngmo Jul 08 '20 at 14:54
  • Very very closely related to https://stackoverflow.com/q/1015678/3266847 – Benjamin W. Jul 08 '20 at 15:11
  • @BenjaminW. Indeed related. I find listing it in reverse order to grab the last entry instead of grabbing the first is a bit odd though. If `head -1` exits at least `ls` gets the chance to quit early (because writing on `stdout` fails). With `tail -1` it _must_ run through the whole list. – Ted Lyngmo Jul 08 '20 at 15:19
  • 1
    @TedLyngmo I'm not saying the highest voted answers on there are good, just that the question is almost identical ;) – Benjamin W. Jul 08 '20 at 15:24
  • See also [BashFAQ/003](https://mywiki.wooledge.org/BashFAQ/003) – Benjamin W. Jul 08 '20 at 15:24
  • What is `Last_UpdatedDateTime`, by the way? Do you have these files, or a table with filenames and these datetime strings? – Benjamin W. Jul 08 '20 at 15:25

2 Answers2

0

You can list files sorted in the order they were modified with ls -t:

 -t     sort by modification time, newest first

You can use globbing (abc*) to match all files starting with abc.

Since you will get more than one match and only want the newest (that is first):

head -1

Combined:

ls -t abc* | head -1
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
0

If there are a lot of these files scattered across a variety of directories, find mind be better.

find -name abc\* -printf "%T@ %f\n" |sort -nr|sed 's/^.* //; q;'

Breaking that out -

find -name 'abc*' -printf "%T@ %f\n" |

find has a ton of options. This is the simplest case, assuming the current directory as the root of the search. You can add a lot of refinements, or just give / to search the whole system.

-name 'abc*' picks just the filenames you want. Quote it to protect any globs, but you can use normal globbing rules. -iname makes the search case-insensitive.

-printf defines the output. %f prints the filename, but you want it ordered on the date, so print that first for sorting so the filename itself doesn't change the order. %T accepts another character to define the date format - @ is the unix epoch, seconds since 00:00:00 01/01/1970, so it is easy to sort numerically. On my git bash emulation it returns fractions as well, so it's great granularity.

$: find -name abc\* -printf "%T@ %f\n"
1594219755.7741618000 abc123
1594219775.5162510000 abc321
1594219734.0162554000 abc456

find may not return them in the order you want, though, so -

sort -nr | 

-n makes it a numeric sort. -r sorts in reverse order, so that the latest file will pop out first and you can ignore everything after that.

sed 's/^.* //; q;'

Since the first record is the one we want, sed can just use s/^.* //; to strip off everything up to the space, which we know will be the timestamp numbers since we controlled the output explicitly. That leaves only the filename. q explicitly quits after the s/// scrubs the record, so sed spits out the filename and stops without reading the rest, which prevents the need for another process (head -1) in the pipeline.

Paul Hodges
  • 13,382
  • 1
  • 17
  • 36