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


11

即使大多数外壳程序在“ POSIX模式”下运行,内置的test[实用程序在大多数外壳程序中都具有-nt(“比...更新”)和-ot(“比...更旧”)测试(对于在外壳上使用相同名称的外部实用程序也是如此)我可以访问的系统)。这些测试用于比较两个文件上的修改时间戳。它们的文档化语义在不同的实现中略有不同(关于一个或另一个文件不存在的情况),但是它们不包含在POSIX规范中。为test实用

他们不结转到test时,从[KornShell]壳去除有条件的命令,因为他们没有被列入工具test内置于历史实现实用sh工具。

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

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

...除了make(这至少会使脚本的其余部分难以理解)之外,我还可以使用其他什么实用程序?还是我应该假设没有人会在“的历史实现sh” 上运行脚本,或者辞职以编写像这样的特定 shell bash


正如您在我的答案中看到的那样,bash并没有以自预期以来的方式实现的-nt功能test。1995。find即使bash您喜欢正确的行为,也应该使用basd表达式。
schily

Answers:


10

适当地:

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 . \;

从技术上讲,我认为如果$f1仅包含换行符,它就会失败;)
ilkkachu

1
@ilkkachu可以解决-exec echo x \;类似问题吗?
大师

@muru,是的。-printf如果是标准的话,这将很容易
ilkkachu

3
@Kusalananda AFAICT find的退出状态与各个find收益测试的结果无关,除非实际运行这些测试时可能有错误。find即使找不到文件也退出0。
大师

1
注意,行为[ / -nt /nofile ]随实现而变化(但从不输出任何错误)。
斯特凡Chazelas

7

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

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

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


3
如果文件名以-(missing --)开头,则不起作用。您需要-L将其等同于-nt。这并不工作,比较x$'x\nx'举例。
斯特凡Chazelas

1
ek!也是吧。
库沙兰南达

4

您提出了一个有趣的问题,并提出了一个应首先进行验证的主张。

我检查了以下行为:

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

与各种贝壳。结果如下:

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

  • 波什 作品

  • 破折号不起作用-不打印任何内容。

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

  • ksh93 作品

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

  • 高档打印:高档:[:-nt:意外的运算符/操作数

  • yash 工程

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

因此,九个shell中的四个支持-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,我不能说所有make的实现,但是SunPro Make自从大约开始,我就支持纳秒级的时间比较。20年的时间,最近smakegmake添加了此功能。


1
是因为无法比较亚秒级的时间戳(肯定是?),还是其他原因导致“无效”测试无效?测试中涉及的文件的实际时间戳是多少?+1测试!
库萨兰南达

2
我认为反对意见可能与对抗性措辞有关。在这里,将其称为限制(在某些情况下很重要)会更公平。find诸如busybox或heirloom-toolchest之类的某些实现将具有相同的限制。
斯特凡Chazelas

3
您需要-Lfind版本等同于-nt。它也无法在与开始的文件名-或者!(...
斯特凡Chazelas

2
事实上,当我使用对抗性措辞时,我的确会感到不满。在这里,如果您在答案的开头声明了上下文(截断为第二个分辨率时在同一时间戳内修改的文件),将很有帮助。
斯特凡Chazelas

1
@schily,是的,BSD find可以find -f "$file"做到这一点,但是它不是可移植的。
斯特凡Chazelas
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.