thiru thiru - 1 year ago 57
Bash Question

find the latest modified file and exec

I want to find out the latest built rpm in a directory and then exec something on it. Something similar to below.

/bin/ls -1t srcdir/*.rpm | head -1

But with the find command

find srcdir/*.rpm <get-only-the-most-recently-modified-file> -exec "<do-something>"

Answer Source

Two approaches -- one portable to non-GNU platforms, the other fast with large directories (to the extent allowed by the filesystem):



BashFAQ #3: How can I sort or compare files based on some metadata attribute (newest / oldest modification time, size, etc)? is relevant here. To summarize:

for f in "$srcdir"/*.rpm; do
  [ "$f" -nt "$latest" ] && latest=$f


[ "$a" -nt "$b" ] checks whether the file named in variable a is newer than that named in variable b in ksh-derived shells.

Fast be clear, this is faster with very large directories, as opposed to faster in all cases. That said, it's also easily adapted to find (for instance) the 5 or 10 newest files, or all files except those 5 or 10 newest, which the other approach could not do nearly as effectively.


If you have GNU tools (GNU find, GNU sort), consider the following:

{ read -r -d ' ' mtime && IFS= read -r -d '' filename; } \
  < <(find /directory -type f -iname "*.rpm" -printf '%T@ %p\0' | sort -z -r -n)

This will put your latest file's time (in seconds-since-epoch) in the shell variable mtime and the name of that file in filename. Thus, you can then operate on that file:

if [[ -e $filename ]]; then
  # do whatever arbitrary operations you're looking for on that resulting filename
  cp -- "$filename" /path/to/where/to/copy


To explain how this works:

find ... -printf '%T@ %p\0'

...emits contents in the format <epoch_mtime> <filename><NUL>, where epoch_mtime is the number of seconds since January 1st, 1970.

sort -z -r -n

...then sorts that output, expecting it to be NUL-delimited, on the numbers at the beginning.

{ read -r -d ' ' mtime && IFS= read -r -d '' filename; }

...reads content into the mtime variable up to the first space in the first line, and then reads forward to the first NUL into the filename variable.