在Linux上的目录中获取最新文件


178

寻找一个将返回目录中最新文件的命令。

没有看到ls的限制参数...


1
watch -n1 'ls -Art | tail -n 1'-显示最后一个文件

Answers:


262
ls -Art | tail -n 1

不是很优雅,但可以。


2
使用ls -Artls也可以查看文件日期。
乔西(Josir)2014年

13
一个小问题:此版本将的所有输出ls传递给tail,然后仅打印LAST行。恕我直言,最好按升序排序并head按照chaos建议使用。打印后,第一行打印头退出,因此发送下一行(实际上是下一个块)将引发SIGPIPE并ls也退出。
TrueY

1
@TrueY我完全同意。混沌的答案更好地提高了效率。
dmckee ---前主持人小猫,2014年

2
请注意,此解决方案包括目录和文件。这可能是好事或坏事。这取决于个人用户的需求。我提出这个问题的原因是原始问题是“文件”。
Sildoreth

2
我认为使用tail而不是head的预期好处可能是排除了描述ls返回的总数的行。
彼得·斯科特

151
ls -t | head -n1

该命令实际上在当前工作目录中提供最新的修改文件。


相当于我的,并且可能也更有效。
dmckee ---前主持人小猫,

因为我先在我的ls中回显了一些信息,但它对我来说并不起作用,但是我得到了用法,谢谢!
确认

4
@Josir可以将其修改为包括带有的datestamp ls -tl | head -n 1,而不必像我的那样将整个表推入管道。
dmckee ---前主持人小猫,2014年

1
@noɥʇʎԀʎzɐɹƆ– ls -t *.png | head -n1
混乱

4
如果它是最新修改的文​​件,则返回一个文件夹,请使用:ls -Art | head -n1如果您特别想要最新修改的文​​件
achasinh

79

这是一个递归版本(即,它在某个目录或其任何子目录中找到最新更新的文件)

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

编辑:使用-f 2-而不是-f 2凯文建议


5
这是Mac的解决方案:find $DIR -type f -exec stat -lt "%Y-%m-%d" {} \+ | cut -d' ' -f6- | sort -n | tail -1
用户

2
问题是cut命令将使用空格而不是-f 2截断路径,而使用-f2-将字段2返回到行尾
Kevin

2
就像混乱中的建议一样,如果您使用来反转排序sort -nr,则可以使用head -n 1代替tail -n 1并稍微提高效率。(尽管如果您对递归查找进行排序,则获取第一行或最后一行不会是很慢的部分。)
destenson

2
很有用!如果通过管道传输到ls,我发现它更友好:find ./ -type f -printf "%T@ %p\n" -ls | sort -n | cut -d' ' -f 2- | tail -n 1 | xargs -r ls -lah
Simon

@user的Mac版本仅排序/显示日期,而不是时间。这是固定版本:find $DIR -type f -exec stat -lt "%F %T" {} \+ | cut -d' ' -f6- | sort -n | tail -1
yoz

11

关于可靠性的注意事项:

由于换行字符是一样有效的任何文件名中,依赖于任何溶液线head/tail基础的人都是有缺陷的。

对于GNU ls,另一种选择是使用--quoting-style=shell-always选项和一个bash数组:

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

(将-A选项添加到ls如果您还想考虑隐藏文件,请)。

如果您想限制常规文件(忽略目录,fifos,设备,符号链接,套接字...),则需要使用GNU find

对于bash 4.4或更高版本(用于readarray -d)和GNU coreutils 8.25或更高版本(用于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]}"

或递归地:

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

最好的办法是使用zsh及其限定符而不是bash避免所有这些麻烦:

当前目录中的最新常规文件:

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

包括隐藏的:

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

第二最新:

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

解析符号链接后检查文件年龄:

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

递归地:

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

另外,compinit启用完成系统(和共同)后,Ctrl+Xm会成为一个扩展程序,扩展为最新文件。

所以:

Ctrl+Xm

使您可以编辑最新文件(在按之前,您还可以查看该文件 Return)。

Alt+2Ctrl+Xm

对于第二最新的文件。

vi * .cCtrl+Xm

最新的 c文件。

vi *(。)Ctrl+Xm

以获取最新的常规文件(不是目录,也不是fifo / device ...),依此类推。


感谢您的zsh提示。您能否在zsh docs中提供有关此详细信息的链接?
4

@freezed,请参阅info zsh qualifiers
Stephane Chazelas

感谢@Stephane Chazelas
4

9

我用:

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

它只给我文件名,不包括文件夹。


除非目录中只有目录
ealfonso 2013年

8

ls -lAtr | tail -1

其他解决方案不包括以以下内容开头的文件 '.'

此命令还将包括'.''..',可能不是您想要的:

ls -latr | tail -1


这个会返回“。” 目录的修改是否比包含的任何文件更新(例如删除)?也许这是期望的行为,也许不是。但是,无论哪种方式,您都是对的。
dmckee ---前主持人小猫,


5

我喜欢 echo *(om[1])zsh语法),因为它仅提供文件名,而不调用任何其他命令。


1
如果使用zsh,效果很好。您不使用zsh吗?我认为bash是Ubuntu中的默认设置;您可以安装zsh,也可以找到等效的bash命令。
MikeB

3
命令是“ echo”;它只是评估其参数并将其发送到标准输出。在这种情况下,全局限定符“ om [1]”具有“ o”,这意味着将匹配的文件按“ m”排序,这是修改时间。然后从该有序列表中选取[1],这是第一个文件。您可以阅读有关glob限定词的信息:zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers
MikeB 2014年

4

在文件数量变得非常大之前(例如整个文件系统),查找/排序解决方案非常有效。请改用awk来跟踪最新文件:

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]* //'

3

我个人更喜欢使用尽可能少的非内置bash命令(以减少昂贵的fork和exec syscalls的数量)。按日期排序ls需要调用的内容。但是使用of head并不是真正必要的。我使用以下一线(仅在支持名称管道的系统上工作):

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

或获取最早的文件的名称

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

(请注意两个“ <”标记之间的空格!)

如果还需要隐藏文件,则可以添加-arg。

我希望这会有所帮助。


您应该说明文件名存储在$ oldest / newest var中。但是+1的分叉数量最少。
squareatom

我认为阅读的@squareatom是内置的。但是你是对的,也许不是。谢谢你的评论!
TrueY

3
假设您知道内建的内容,那是正确的。但是,我只是在考虑OP的问题。他们要求一个返回内容的命令。从技术上讲,您的解决方案不会输出任何内容。因此,只需在末尾添加“ && echo $ newest”或类似的内容即可;-)
squareatom

3

使用R递归选项..您可以将其视为增强功能,以获得良好的答案

ls -arRtlh | tail -50


2

递归地:

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



0

所有这些ls / tail解决方案都能完美地处理文件中文件 -忽略子目录。

为了将所有文件包括在搜索中(递归),可以使用find。gioele建议对格式化的查找输出进行排序。但是要注意空格(他的建议不适用于空格)。

这应该适用于所有文件名:

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

这按mtime排序,请参见man查找:

%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.

因此,只需更换%T%C通过的ctime排序。


您对@gioele建议的空格问题是正确的,但是您只需在-f选项中添加连字符以使其成为解决以下问题的范围: find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1 或者,保留除第一个字段以外的所有内容: find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 1 --complement | tail -n 1
Aaron

0

根据模式在每个目录中查找最新文件,例如,工作目录的子目录名称以“ tmp”结尾(不区分大小写):

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

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

1
还提供了OP的问题的其他答案,并且这些答案已在多年前发布。发布答案时,请确保添加新的解决方案或实质上更好的解释,尤其是在回答较旧的问题时。
help-info.de

2
@ help-info.de请不要投票删除仅代码的答案。它们可能不是很好,但是删除是针对
无法解决的

@Machavity-我希望不会失败,并且只对以后的回答发表评论。
help-info.de

0

如果要获取最近更改的文件(包括所有子目录),则可以使用此小内衬纸进行操作:

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

如果您不想对已更改的文件执行相同的操作,但是对于已访问的文件,则只需更改

stat命令中的%Y参数到%X。您最近访问的文件的命令如下所示:

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

对于两个命令,如果要列出多个文件,还可以更改var =“ 1”参数。


-1

我也需要这样做,并且找到了这些命令。这些为我工作:

如果要在文件夹中创建文件的最后日期(访问时间):

ls -Aru | tail -n 1  

而且,如果您希望最后一个文件的内容发生变化(修改时间):

ls -Art | tail -n 1  
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.