在 POSIX sh 中执行 -nt/-ot 测试

在 POSIX sh 中执行 -nt/-ot 测试

内置test[实用程序在大多数 shell 中都具有-nt(“更新于”)和-ot(“旧于”)测试,即使 shell 在“POSIX 模式”下运行(对于外部同名实用程序也是如此)我有权访问的系统)。这些测试用于比较两个文件的修改时间戳。它们记录的语义在不同的实现中略有不同(关于如果一个或另一个文件存在或不存在时会发生什么),但它们不包含在POSIX 规范。对于test公用事业

当条件命令从 [KornShell] shell 中删除时,它们不会被转移到test实用程序中,因为它们尚未包含在test实用程序历史实现中内置的实用程序中sh

假设我想比较/bin/shshell 脚本中文件之间的修改时间戳,然后根据一个文件是否比另一个文件新来采取行动,如下所示

if [ "$sigfile"     -nt "$timestamp" ] ||
   [ "$sigfile.tmp" -nt "$timestamp" ]
then
    return
fi

...除了make(至少可以说这会使脚本的其余部分变得难以处理)之外,我还可以使用什么其他实用程序?或者我应该假设没有人会在“历史实现sh”上运行脚本,或者放弃为一个具体的外壳像bash

答案1

正面:

f1=/path/to/file_1
f2=/path/to/file_2

if [ -n "$(find -L "$f1" -prune -newer "$f2")" ]; then
    printf '%s is newer than %s\n' "$f1" "$f2"
fi

使用文件的绝对路径可以防止文件名仅包含换行符的误报。

如果使用相对路径,则将find命令更改为:

find -L "$f1" -prune -newer "$f2" -exec echo . \;

答案2

这可能是使用最古老的 Unix 命令之一的情况ls

x=$(ls -tdL -- "$a" "$b")
[ "$x" = "$a
$b" ]

如果 a 比 b 新,则结果为 true。

答案3

您提出了一个有趣的问题并提出了一个应该首先得到验证的主张。

我检查了以下行为:

$shell -c '[ Makefile -nt SCCS/s.Makefile ] && echo newer'

与各种贝壳。结果如下:

  • 巴什不起作用 - 不打印任何内容。

  • 波什 作品

  • 短跑不起作用 - 不打印任何内容。

  • 克什88不起作用 - 不打印任何内容。

  • 克什93 作品

  • 姆克什不起作用 - 不打印任何内容。

  • 豪华打印: posh: [: -nt: 意外的运算符/操作数

  • 亚什 作品

  • 桀骜 适用于较新的版本,旧版本不打印任何内容

所以九个壳中有四个支持-nt功能并正确实施。在这种情况下正确意味着:能够比较支持亚秒级时间戳粒度的最新平台上的时间戳。请注意,我选择的文件的时间戳通常仅存在几微秒的差异。

由于更容易找到有效的find实现,我建议替换

if [ "$file1" -nt "$file2" ] ; then
    echo newer
fi

通过find基于表达式。

if [ "$( find "$file1" -newer "$file2" )" ]; then
    echo newer
fi

至少只要$file1不包含换行符就可以工作。

if [ "$( find -L "$file1" -newer "$file2" -exec echo newer \; )" ]; then
    echo newer
fi

有点慢但工作正常。

顺便提一句:关于品牌我不能代表所有 make 实现,但SunPro Make支持与纳秒粒度的时间比较,因为大约。 20 年过去了,最近smakegmake添加了这个功能。

相关内容