Get most recent file in a directory on Linux
LinuxShellCommand LineLinux 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 shellpipe
(seeman bash
section onPipelines
)sort -n
means to sort on the first column and to treat the token as numerical instead of lexicographic (seeman sort
)cut -d' ' -f 2-
means to split each line using theman cut
)- NOTE:
-f 2
would print only the second token
- NOTE:
tail -n 1
means to print the last line (seeman 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