Get most recent file in a directory on Linux

LinuxShellCommand Line

Linux Problem Overview


Looking for a command that will return the single most recent file in a directory.

Not seeing a limit parameter to ls...

Linux Solutions


Solution 1 - Linux

ls -Art | tail -n 1

Not very elegant, but it works.

Used flags:

-A list all files except . and ..

-r reverse order while sorting

-t sort by time, newest first

Solution 2 - Linux

ls -t | head -n1

This command actually gives the latest modified file in the current working directory.

Solution 3 - Linux

This is a recursive version (i.e. it finds the most recently updated file in a certain directory or any of its subdirectory)

find /dir/path -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1

Brief layman explanation of command line:

  • find /dir/path -type f finds all the files in the directory
    • -printf "%T@ %p\n" prints a line for each file where %T@ is the float seconds since 1970 epoch and %p is the filename path and \n is the new line character
    • for more info see man find
  • | is a shell pipe (see man bash section on Pipelines)
  • sort -n means to sort on the first column and to treat the token as numerical instead of lexicographic (see man sort)
  • cut -d' ' -f 2- means to split each line using the character and then to print all tokens starting at the second token (see man cut)
    • NOTE: -f 2 would print only the second token
  • tail -n 1 means to print the last line (see man tail)

Solution 4 - Linux

A note about reliability:

Since the newline character is as valid as any in a file name, any solution that relies on lines like the head/tail based ones are flawed.

With GNU ls, another option is to use the --quoting-style=shell-always option and a bash array:

eval "files=($(ls -t --quoting-style=shell-always))"
((${#files[@]} > 0)) && printf '%s\n' "${files[0]}"

(add the -A option to ls if you also want to consider hidden files).

If you want to limit to regular files (disregard directories, fifos, devices, symlinks, sockets...), you'd need to resort to GNU find.

With bash 4.4 or newer (for readarray -d) and GNU coreutils 8.25 or newer (for cut -z):

readarray -t -d '' files < <(
  LC_ALL=C find . -maxdepth 1 -type f ! -name '.*' -printf '%T@/%f\0' |
  sort -rzn | cut -zd/ -f2)

((${#files[@]} > 0)) && printf '%s\n' "${files[0]}"

Or recursively:

readarray -t -d '' files < <(
  LC_ALL=C find . -name . -o -name '.*' -prune -o -type f -printf '%T@%p\0' |
  sort -rzn | cut -zd/ -f2-)

Best here would be to use zsh and its glob qualifiers instead of bash to avoid all this hassle:

Newest regular file in the current directory:

printf '%s\n' *(.om[1])

Including hidden ones:

printf '%s\n' *(D.om[1])

Second newest:

printf '%s\n' *(.om[2])

Check file age after symlink resolution:

printf '%s\n' *(-.om[1])

Recursively:

printf '%s\n' **/*(.om[1])

Also, with the completion system (compinit and co) enabled, Ctrl+Xm becomes a completer that expands to the newest file.

So:

vi Ctrl+Xm

Would make you edit the newest file (you also get a chance to see which it before you press Return).

vi Alt+2Ctrl+Xm

For the second-newest file.

vi *.cCtrl+Xm

for the newest c file.

vi *(.)Ctrl+Xm

for the newest regular file (not directory, nor fifo/device...), and so on.

Solution 5 - Linux

I use:

ls -ABrt1 --group-directories-first | tail -n1

It gives me just the file name, excluding folders.

Solution 6 - Linux

ls -lAtr | tail -1

The other solutions do not include files that start with '.'.

This command will also include '.' and '..', which may or may not be what you want:

ls -latr | tail -1

Solution 7 - Linux

I like echo *(om[1]) (zsh syntax) as that just gives the file name and doesn't invoke any other command.

Solution 8 - Linux

The find / sort solution works great until the number of files gets really large (like an entire file system). Use awk instead to just keep track of the most recent file:

find $DIR -type f -printf "%T@ %p\n" | 
awk '
BEGIN { recent = 0; file = "" }
{
if ($1 > recent)
   {
   recent = $1;
   file = $0;
   }
}
END { print file; }' |
sed 's/^[0-9]*\.[0-9]* //'

Solution 9 - Linux

Shorted variant based on dmckee's answer:

ls -t | head -1

Solution 10 - Linux

If you want to get the most recent changed file also including any subdirectories you can do it with this little oneliner:

find . -type f -exec stat -c '%Y %n' {} \; | sort -nr | awk -v var="1" 'NR==1,NR==var {print $0}' | while read t f; do d=$(date -d @$t "+%b %d %T %Y"); echo "$d -- $f"; done

If you want to do the same not for changed files, but for accessed files you simple have to change the

%Y parameter from the stat command to %X. And your command for most recent accessed files looks like this:

find . -type f -exec stat -c '%X %n' {} \; | sort -nr | awk -v var="1" 'NR==1,NR==var {print $0}' | while read t f; do d=$(date -d @$t "+%b %d %T %Y"); echo "$d -- $f"; done

For both commands you also can change the var="1" parameter if you want to list more than just one file.

Solution 11 - Linux

I personally prefer to use as few not built-in bash commands as I can (to reduce the number of expensive fork and exec syscalls). To sort by date the ls needed to be called. But using of head is not really necessary. I use the following one-liner (works only on systems supporting name pipes):

read newest < <(ls -t *.log)

or to get the name of the oldest file

read oldest < <(ls -rt *.log)

(Mind the space between the two '<' marks!)

If the hidden files are also needed -A arg could be added.

I hope this could help.

Solution 12 - Linux

using R recursive option .. you may consider this as enhancement for good answers here

ls -arRtlh | tail -50

Solution 13 - Linux

With only Bash builtins, closely following BashFAQ/003:

shopt -s nullglob

for f in * .*; do
	[[ -d $f ]] && continue
	[[ $f -nt $latest ]] && latest=$f
done

printf '%s\n' "$latest"

Solution 14 - Linux

try this simple command

ls -ltq  <path>  | head -n 1

If you want file name - last modified, path = /ab/cd/*.log

If you want directory name - last modified, path = /ab/cd/*/

Solution 15 - Linux

ls -t -1 | sed '1q'

Will show the last modified item in the folder. Pair with grep to find latest entries with keywords

ls -t -1 | grep foo | sed '1q'

Solution 16 - Linux

Recursively:

find $1 -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head

Solution 17 - Linux

Finding the most current file in every directory according to a pattern, e.g. the sub directories of the working directory that have name ending with "tmp" (case insensitive):

find . -iname \*tmp -type d -exec sh -c "ls -lArt {} | tail -n 1" \;

Solution 18 - Linux

Presuming you don't care about hidden files that start with a .

ls -rt | tail -n 1

Otherwise

ls -Art | tail -n 1

Solution 19 - Linux

ls -Frt | grep "[^/]$" | tail -n 1

Solution 20 - Linux

All those ls/tail solutions work perfectly fine for files in a directory - ignoring subdirectories.

In order to include all files in your search (recursively), find can be used. gioele suggested sorting the formatted find output. But be careful with whitespaces (his suggestion doesn't work with whitespaces).

This should work with all file names:

find $DIR -type f -printf "%T@ %p\n" | sort -n | sed -r 's/^[0-9.]+\s+//' | tail -n 1 | xargs -I{} ls -l "{}"

This sorts by mtime, see man find:

%Ak    File's  last  access  time in the format specified by k, which is either `@' or a directive for the C `strftime' function.  The possible values for k are listed below; some of them might not be available on all systems, due to differences in `strftime' between systems.
       @      seconds since Jan. 1, 1970, 00:00 GMT, with fractional part.
%Ck    File's last status change time in the format specified by k, which is the same as for %A.
%Tk    File's last modification time in the format specified by k, which is the same as for %A.

So just replace %T with %C to sort by ctime.

Solution 21 - Linux

I needed to do it too, and I found these commands. these work for me:

If you want last file by its date of creation in folder(access time) :

ls -Aru | tail -n 1  

And if you want last file that has changes in its content (modify time) :

ls -Art | tail -n 1  

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionackView Question on Stackoverflow
Solution 1 - Linuxdmckee --- ex-moderator kittenView Answer on Stackoverflow
Solution 2 - LinuxchaosView Answer on Stackoverflow
Solution 3 - LinuxgioeleView Answer on Stackoverflow
Solution 4 - LinuxStephane ChazelasView Answer on Stackoverflow
Solution 5 - Linuxuser1195354View Answer on Stackoverflow
Solution 6 - LinuxJared OberhausView Answer on Stackoverflow
Solution 7 - LinuxMikeBView Answer on Stackoverflow
Solution 8 - LinuxPatrickView Answer on Stackoverflow
Solution 9 - LinuxDmytro G. SergiienkoView Answer on Stackoverflow
Solution 10 - LinuxOASE Software GmbHView Answer on Stackoverflow
Solution 11 - LinuxTrueYView Answer on Stackoverflow
Solution 12 - LinuxmebadaView Answer on Stackoverflow
Solution 13 - LinuxBenjamin W.View Answer on Stackoverflow
Solution 14 - LinuxRICHA AGGARWALView Answer on Stackoverflow
Solution 15 - LinuxRichard ServelloView Answer on Stackoverflow
Solution 16 - LinuxKonkiView Answer on Stackoverflow
Solution 17 - Linuxxb.View Answer on Stackoverflow
Solution 18 - LinuxjasonleonhardView Answer on Stackoverflow
Solution 19 - LinuxJoão FonsecaView Answer on Stackoverflow
Solution 20 - Linuxbasic6View Answer on Stackoverflow
Solution 21 - Linuxmasoomeh vahidView Answer on Stackoverflow