33

How do I find out the most recently accessed file in a given directory?

I can use the find command to list out all files modified/accessed in last n minutes. But here in my case, I'm not sure when the last file was modified/accessed? All that I need is to list all the files which were accessed/modified very recently among all other sub-files or sub-directories, sorted by their access/modified times, for example.

Is that possible?

1
  • Your question is unclear. Are you saying you want to take the list of files from find and sort them by date?
    – RobertL
    Nov 3, 2015 at 7:19

7 Answers 7

28

To print the last 3 accessed files (sorted from the last accessed file to the third last accessed file):

find . -type f -exec stat -c '%X %n' {} \; | sort -nr | awk 'NR==1,NR==3 {print $2}'

To print the last 3 modified files (sorted from the last modified file to the third last modified file):

find . -type f -exec stat -c '%Y %n' {} \; | sort -nr | awk 'NR==1,NR==3 {print $2}'
  • find . -type f -exec stat -c '%X %n' *: prints the last access' time followed by the file's path for each file in the current directory hierarchy;
  • find . -type f -exec stat -c '%Y %n' *: prints the last modification's time followed by the file's path for each file in the current directory hierarchy;
  • sort -nr: sorts in an inverse numerical order;
  • awk 'NR==1,NR==3 {print $2}': prints the second field of the first, second and third line.

You can change the number of files to be shown by changing 3 to the desired number of files in awk 'NR==1,NR==3 {print $2}'.

% touch file1
% touch file2
% touch file3
% find . -type f -exec stat -c '%X %n' {} \; | sort -nr | awk 'NR==1,NR==3 {print }'
./file3
./file2
./file1
% find . -type f -exec stat -c '%Y %n' {} \; | sort -nr | awk 'NR==1,NR==3 {print }'
./file3
./file2
./file1
% cat file1
% find . -type f -exec stat -c '%X %n' {} \; | sort -nr | awk 'NR==1,NR==3 {print }'
./file1
./file3
./file2
% find . -type f -exec stat -c '%Y %n' {} \; | sort -nr | awk 'NR==1,NR==3 {print }'
./file3
./file2
./file1
% touch file2
% find . -type f -exec stat -c '%X %n' {} \; | sort -nr | awk 'NR==1,NR==3 {print }'
./file2
./file1
./file3
% find . -type f -exec stat -c '%Y %n' {} \; | sort -nr | awk 'NR==1,NR==3 {print }'
./file2
./file3
./file1
7
  • Command is not honouring the year
    – SHW
    Nov 3, 2015 at 8:22
  • @SHW Not sure what you mean. The files are sorted based on the number of seconds passed from January 1st 1970.
    – kos
    Nov 3, 2015 at 8:28
  • Works on Mac OS X but with a slight tweak to the stat command: stat -f '%Dm %N' Jan 10, 2019 at 18:47
  • To help other users: if you want to scan another directory than the current directory, replace the . directly after the find. It took me a couple of minutes to understand it. Dec 12, 2019 at 14:59
  • 3
    These commands break for filenames that contains whitespaces. The culprit is awk and as I don’t know how to use it, simply replacing the awk command with | head -n 3 (to keep the first three results) does the trick. If you stil want to remove the timestamps, chain it with | cut -d' ' -f2-
    – Maëlan
    Mar 20, 2020 at 15:42
11

If you want the files in a given directory sorted by modification age (most recent first):

ls -t

To sort by access time, add the -u option.

ls -tu

However, beware that modern Linux systems do not track exact access times by default. So the access timestamps may not be reliable.

If you want to find the most recent file within a directory tree, including subdirectories, the easiest method by far is to use zsh's glob qualifiers.

print -lr -- **/*(om)

Use oa instead of om to use the access time rather than the modification time. You can restrict the matches, for example to get the 10 most recent files:

print -lr -- **/*(om[1,10])

Those skip hidden files. If you want to also consider hidden files, add the D glob qualifier. You can also add the . glob qualifier to only consider regular files (not consider symlinks, directories, fifos...), and mm-60 or mh-1 to restrict to files last modified within the last hour.

10

You could use the recursive switch (-R) to ls along with the sort by time switch (-t) and the reverse sort switch (-r) to list out all the files in a directory tree. This will not sort all the files by their access/modify dates across sub-directories, but will sort them by this date within each sub-directory independently.

Using a command such as this: ls -ltrR <sometopdir>.

Example

$ ls -ltrR .
total 759720
-rw-r-----@  1 sammingolelli  staff    2514441 Mar 31  2015 restfulapi-120704053212-phpapp01.pdf
-rw-r-----@  1 sammingolelli  staff     567808 Apr  7  2015 USGCB-Windows-Settings.xls
-rw-r-----@  1 sammingolelli  staff     180736 Apr  7  2015 USGCB-RHEL5-Desktop-Settings-Version-1.2.5.0.xls
-rw-r-----@  1 sammingolelli  staff       6474 Apr  8  2015 tap_kp_mavericks.txt

./kerberos:
total 5464
-rw-r-----@ 1 sammingolelli  staff    37317 Oct  2 13:03 Set_up_Kerberos_instruction_d8.docx
-rw-r-----@ 1 sammingolelli  staff  2753195 Oct 13 13:49 Keberos configuration with AD 01_09_2014.pdf

./homestarrunner:
total 10624
-rw-rw-rw-@ 1 sammingolelli  staff   319422 May 10  2000 error_hs.wav
-rw-rw-rw-@ 1 sammingolelli  staff    53499 Jun  8  2001 sb_duck.mp3
-rw-rw-rw-@ 1 sammingolelli  staff   199254 Mar 11  2002 email_sb.wav
-rw-rw-rw-@ 1 sammingolelli  staff    39288 Mar 25  2002 bubs_dontutalk.mp3
-rw-rw-rw-@ 1 sammingolelli  staff    75432 May  6  2002 trash_sb.wav
-rw-rw-rw-@ 1 sammingolelli  staff   298946 Dec  1  2002 error_sb.wav
-rw-rw-rw-@ 1 sammingolelli  staff   298686 Dec  1  2002 startup_hs.wav
-rw-rw-rw-@ 1 sammingolelli  staff    90279 Dec  1  2002 sb_meedlymee.mp3
-rw-rw-rw-@ 1 sammingolelli  staff    73561 Dec  1  2002 sb_dubdeuce.mp3
-rw-rw-rw-@ 1 sammingolelli  staff   193097 Dec  1  2002 sb_pizza.mp3
-rw-rw-rw-@ 1 sammingolelli  staff    30093 Dec  1  2002 sb_stiny.mp3
-rw-rw-rw-@ 1 sammingolelli  staff    61858 Dec  1  2002 ss_sadflying.mp3
-rw-rw-rw-@ 1 sammingolelli  staff   150142 Dec  1  2002 email_hs.wav
-rw-rw-rw-@ 1 sammingolelli  staff    68545 Dec  1  2002 bubs_grabbinbutt.mp3
-rw-rw-rw-@ 1 sammingolelli  staff    61022 Dec  1  2002 cz_jeorghb.mp3
-rw-rw-rw-@ 1 sammingolelli  staff    40124 Dec  1  2002 marzy_nasty.mp3
-rw-rw-rw-@ 1 sammingolelli  staff   224116 Dec  1  2002 shutdown_sb.wav
-rw-rw-rw-@ 1 sammingolelli  staff   260546 Dec  1  2002 shutdown_hs.wav
-rw-rw-rw-@ 1 sammingolelli  staff    57686 Dec  1  2002 trash_hs.wav
10

This command also provide the most recently modified file or directory from the current directory tree:

% find . -printf '%TY-%Tm-%TdT%TT %p\n' |sort |tail -1
2019-01-30T17:29:18.0330479800 ./servlet-api/META-INF/NOTICE

Of course, you can change the last argument to the number of most recent files you might need.

2
  • 2
    That only works if you can guarantee none of the file paths will contain newline characters. Also note that as that's printing the timestamps in local time, that could give incorrect results around DST changes. Changing to TZ=UTC0 find . -printf '%TFT%TTZ %p\0' | sort -rz | head -zn1 | tr '\0' '\n' would address those. (-printf, -z are GNU extensions). Mar 21, 2022 at 10:46
  • 2
    (it's nonetheless still significantly better than the currently top-voted answer) Mar 21, 2022 at 12:16
3

You want to sort the full set of "recent" files by their access/modify time, regardless of their location in the file tree?

One way of doing this is to use stat to print the modify time for each file, sort by the result, and then cut the modification time from the results.

This will break for files containing newlines in their names, but for other files here's a solution that will list files modified within the last 60 minutes, ordered from most recently to least recently modified:

find . -type f -mmin -60 -exec stat -c $'%Y\t%n' {} + | sort -nr | cut -f2-
1
  • Note that GNU find had -printf long before a stat command was added to GNU coreutils (with different API from other preexisting stat implementation, and poorer at formatting than GNU find's -printf). Like @RichardO's find -printf answer, it can also give incorrect results if there are files last-modified around DST changes. Mar 21, 2022 at 12:19
1

I used the mentioned "mrf" script from Matt Kneiser for some investigations. Then several files were showed changed as of 2018-12-11. On further investigations i found out that the stated date was not the modified date but the accessed date. According to the stat manual the correct format string on linux is not %X but %Y for the last modified date instead of last access date. Here the manual entries as of 2020-03-17 on debian:

%X     time of last access, seconds since Epoch
%Y     time of last data modification, seconds since Epoch

In my opinion the correct linux statement on your script should look like:

find . -type f -exec stat -c '%Y %n' {} \; | sort -nr | awk -v var="${_n}" 'NR==1,NR==var {print $0}' | while read t f; do d=$(date -d @$t "+%b %d %T %Y"); echo "$d -- $f"; done
2
  • Welcome to the site and thank you for your contribution. Your opening address is directed at the contributor of a different answer; this may confusing for readers as answers will be displayed in any kind of sort order depending on activity, vote counts, and individual user settings. Please reformulate the answer to make it as "self-contained" as possible until you have the required reputation to comment everywhere. You can still refer to it by including a link, see the "share" button below the other answer (assuming I found the right one ;)).
    – AdminBee
    Mar 17, 2020 at 9:10
  • 1
    @AdminBee thank you for your proposal. I added a link to the origin answer which I tried to improve. Hope this helps. Mar 17, 2020 at 13:13
0

Let's put this into a cross-platform bash function:

# Print N most recently modified files in current dir or below
mrf() {
    local _n=${1:-3} # Default to 3
    case $OSTYPE in
        linux*|msys*)
            find . -type f -exec stat -c '%X %n' {} \; | sort -nr | awk -v var="${_n}" 'NR==1,NR==var {print $0}' | while read t f; do d=$(date -d @$t "+%b %d %T %Y"); echo "$d -- $f"; done
        ;;
        darwin*)
            find . -type f -exec stat -f '%Dm %N' {} \; | sort -nr | awk -v var="${_n}" 'NR==1,NR==var {print $2}' | while read f; do stat -f '%Sm -- %N' $f; done
        ;;
     esac
 }

Usage:

$ mrf
Jan 10 11:50:03 2019 -- ./somefile
Jan 10 11:44:24 2019 -- ./nested/dir/file.txt
Jan 10 11:40:50 2019 -- ./anotherfile

$ mrf 5
Jan 10 11:50:03 2019 -- ./somefile
Jan 10 11:44:24 2019 -- ./nested/dir/file.txt
Jan 10 11:40:50 2019 -- ./anotherfile
Jan 10 06:30:22 2019 -- ./otherdir/yetanotherfile
Jan 09 10:00:00 2019 -- ./oldfile

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .