The built-in test and [ utilities have the -nt ("newer than") and -ot ("older than") tests in most shells, even when the shell is running in "POSIX mode" (also true for the external utilities of the same names on the systems that I have access to). These tests are for comparing modification timestamps on two files. Their documented semantics are slightly varying across implementations (with regards to what happens if one or the other file exists on not), but they are not included in the POSIX spec. for the test utility.

They were not carried forward into the test utility when the conditional command was removed from the [KornShell] shell because they have not been included in the test utility built into historical implementations of the sh utility.

Assuming I'd like to compare the modification timestamp between files in a /bin/sh shell script and then take action depending on whether one file is newer than the other, as in

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

... what other utility could I use, apart from make (which would make the rest of the script unwieldy to say the least)? Or should I just assume that nobody is ever going to run the script on a "historical implementation of sh", or resign to writing for a specific shell like bash?

  • As you can see in my answer, bash does not implement the -nt feature of test in a way that is expected since approx. 1995. You should use the find basd expression even with bash if you like correct behavior.
    – schily
    Jun 14, 2018 at 8:39

3 Answers 3




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

Using absolute path to files prevent a false positive with filename contains newlines only.

In case of using relative path, then change find command to:

find -L "$f1" -prune -newer "$f2" -exec echo . \;
  • technically, I think it fails if $f1 only contains newlines ;)
    – ilkkachu
    Jun 14, 2018 at 7:28
  • 1
    @ilkkachu could be worked around with -exec echo x \; or similar?
    – muru
    Jun 14, 2018 at 7:33
  • @muru, yeah. -printf would be easy if it were standard
    – ilkkachu
    Jun 14, 2018 at 7:36
  • 3
    @Kusalananda AFAICT, find's exit status is independent of what the individual tests of find return - except perhaps if there's an error in actually running those tests. find exits 0 even if no files are found.
    – muru
    Jun 14, 2018 at 7:46
  • 1
    Note that the behaviour of [ / -nt /nofile ] varies with the implementation (but never outputs any error). Jun 14, 2018 at 9:04

This could be a case for using one of the oldest Unix command, ls.

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

The result is true if a is newer than b.

  • 3
    That doesn't work if file names start with - (missing --). You'd need -L for it to be equivalent to -nt. That doesn't work to compare x and $'x\nx' for instance. Jun 14, 2018 at 8:47
  • 1
    Eek! But also huh.
    – Kusalananda
    Jun 14, 2018 at 10:23

You raised an interesting question and made a claim that should first be verified.

I checked the behavior of:

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

with various shells. Here are the results:

  • bash Does not work - prints nothing.

  • bosh works

  • dash Does not work - prints nothing.

  • ksh88 Does not work - prints nothing.

  • ksh93 works

  • mksh Does not work - prints nothing.

  • posh prints: posh: [: -nt: unexpected operator/operand

  • yash works

  • zsh works in newer versions, older versions print nothing

So four of nine shells support the -nt feature and implement it correctly. Correctly in this case means: is able to compare time stamps on recent platforms that support sub-second time stamp granularity. Note that the files I selected differ typically only a few microseconds in their time stamps.

Since it is easier to find a working find implementation, I recommend to replace

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

by a find based expression.

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

works at least as long as $file1 does not only contain newlines.

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

is a bit slower but works correctly.

BTW: Regarding make I cannot speak for all make implementations, but SunPro Make supports time comparison with nanosecond granularity since approx. 20 years, while smake and gmake added this feature recently.

  • 1
    Are the "not working" tests not working because of a failure to compare sub-second timestamps (definitely?), or something else? What's the actual timestamps on the files involved in your test? +1 for the testing!
    – Kusalananda
    Jun 14, 2018 at 8:38
  • 3
    I think the downvote is probably about the confrontational wording. Here, it would be fairer to call it a limitation (significant in some contexts). Some find implementations like busybox or heirloom-toolchest will have the same limitation. Jun 14, 2018 at 8:45
  • 3
    You'd need -L for the the find version to be equivalent to -nt. It would also fail on file names that start with - or !, (... Jun 14, 2018 at 8:50
  • 2
    As a matter of fact, I do often get downvotes when I use a confrontational wording. Here it would help if you stated the context (files modified within same timestamp when truncated to second resolution) at the start of the answer. Jun 14, 2018 at 8:52
  • 1
    @schily, yes, BSDs find have find -f "$file" for that but it's not portable. Jun 14, 2018 at 8:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .