为什么 find return 在传递当前目录和路径时会得到不同的排序结果?

Why does find return different, sorted results when passed the current directory versus a path?

我正在尝试编写 shell 命令 returning 最近修改的文件。 但是,该目录中的文件多于 ls 可以直接容纳的文件(因此使用 find,我认为这是通过管道传输到其他命令的正确解决方案)。

在这样做的过程中,我遇到了目录中 运行 find . 和传递目录以查找( find $folder).

这是一个例子:

➜  echo $SHELL
/usr/local/bin/zsh
➜  pwd
/Users/aresnick/Downloads
➜  find . -type f -maxdepth 1 -print0 | xargs -0 ls -t | head -1
./DID_Codebook_2020.pdf
➜  find $(pwd) -type f -maxdepth 1 -print0 | xargs -0 ls -t | head -1
/Users/aresnick/Downloads/Profiles17_MA.pdf
➜  find /Users/aresnick/Downloads -type f -maxdepth 1 -print0 | xargs -0 ls -t | head -1
/Users/aresnick/Downloads/Profiles17_MA.pdf

请注意 DID_Codebook_2020.pdfProfiles17_MA.pdf 不是同一个文件。 我如何解释为什么这些命令似乎 return 不同的结果?

作为参考,这里是目录中 ls -halt | head -5 的输出(包括最近混淆的两个文件)。

➜ ls -halt | head -5
total 51229416
drwxr-xr-x+   92 aresnick  staff   2.9K Oct 12 10:34 ..
drwx------@ 4033 aresnick  staff   126K Oct 12 10:02 .
-rw-r--r--@    1 aresnick  staff   1.7M Oct 12 10:02 DID_Codebook_2020.pdf
-rw-r--r--@    1 aresnick  staff   470K Oct 12 10:00 Profiles17_MA.pdf

仔细观察通过 stat,看来 change 时间实际上比 Profiles17_MA.pdf:

➜  stat -f "ACCESS-%Sa   CHANGE-%Sc %SN" {DID_Codebook_2020.pdf,Profiles17_MA.pdf}
ACCESS-Oct 12 10:02:14 2020   CHANGE-Oct 12 10:02:08 2020 DID_Codebook_2020.pdf
ACCESS-Oct 12 10:02:14 2020   CHANGE-Oct 12 10:02:10 2020 Profiles17_MA.pdf

但是,我不明白这如何解释为什么 find .find ~/Downloads 相比排序顺序会发生变化。

什么给了?我有一种模糊的直觉,这可能与我们正在查看 inode 的更改时间以及包含目录有关改变……一些东西。

提前致谢!请注意,虽然我也对我的特定排序问题的解决方案感兴趣,但我最感兴趣的是了解为什么会出现差异。

xargs 的工作是拆分超过系统可容纳的命令行。为了便于说明,我们假设您有四个文件和一个 OS,其中 ARG_MAX 仅为 25 个字节(尽管在现实生活中它在现代系统中的数量级为兆字节)。然后没有路径,xargs运行

ls -t ./a ./b ./c ./d

但是对于完整路径,命令行必须分成两个调用,以免超过命令行长度的限制:

ls -t /path/to/a /path/to/b
ls -t /path/to/c /path/to/d

当然,如果 d 是您的最新文件,head 仍将 return 是第一个 ls 调用的最新文件。

在具有 GNU find(Linux 等)的系统上,使用其 -printf 选项格式化一个字符串,其中修改时间在文件名之前。

find . -type f -printf "%T+\t%p[=12=]" |
sort -rnz |
perl -n000 's/^[^\t]+\t//; print; exit'

我们按修改时间排序,然后丢弃修改时间,只打印文件名。空定界符负责处理其中包含换行符的文件名;此功能尤其是 GNU 扩展。

如果您没有 GNU 实用程序,您可以使用 find -exec stat 和类似的格式字符串;不幸的是,stat 的这个特性也没有标准化,但是不难找到 non-Linux 系统的例子,比如 BSD、macOS 等