Performing -nt/-ot test in a POSIX sh
Clash Royale CLAN TAG#URR8PPP
up vote
10
down vote
favorite
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 thetest
utility built into historical implementations of thesh
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" ]
then
return
fi
... 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
?
files timestamps posix test
add a comment |Â
up vote
10
down vote
favorite
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 thetest
utility built into historical implementations of thesh
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" ]
then
return
fi
... 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
?
files timestamps posix test
As you can see in my answer, bash does not implement the-nt
feature oftest
in a way that is expected since approx. 1995. You should use thefind
basd expression even withbash
if you like correct behavior.
â schily
Jun 14 at 8:39
add a comment |Â
up vote
10
down vote
favorite
up vote
10
down vote
favorite
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 thetest
utility built into historical implementations of thesh
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" ]
then
return
fi
... 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
?
files timestamps posix test
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 thetest
utility built into historical implementations of thesh
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" ]
then
return
fi
... 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
?
files timestamps posix test
edited Jun 14 at 8:41
asked Jun 14 at 6:57
Kusalananda
101k13199312
101k13199312
As you can see in my answer, bash does not implement the-nt
feature oftest
in a way that is expected since approx. 1995. You should use thefind
basd expression even withbash
if you like correct behavior.
â schily
Jun 14 at 8:39
add a comment |Â
As you can see in my answer, bash does not implement the-nt
feature oftest
in a way that is expected since approx. 1995. You should use thefind
basd expression even withbash
if you like correct behavior.
â schily
Jun 14 at 8:39
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 at 8:39
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 at 8:39
add a comment |Â
3 Answers
3
active
oldest
votes
up vote
8
down vote
accepted
POSIXLY:
f1=/path/to/file_1
f2=/path/to/file_2
if [ -n "$(find -L "$f1" -prune -newer "$f2")" ]; then
printf '%s is newer than %sn' "$f1" "$f2"
fi
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 at 7:28
1
@ilkkachu could be worked around with-exec echo x ;
or similar?
â muru
Jun 14 at 7:33
@muru, yeah.-printf
would be easy if it were standard
â ilkkachu
Jun 14 at 7:36
3
@Kusalananda AFAICT,find
's exit status is independent of what the individual tests offind
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 at 7:46
1
Note that the behaviour of[ / -nt /nofile ]
varies with the implementation (but never outputs any error).
â Stéphane Chazelas
Jun 14 at 9:04
 |Â
show 10 more comments
up vote
7
down vote
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 comparex
and$'xnx'
for instance.
â Stéphane Chazelas
Jun 14 at 8:47
I added those, thanks.
â meuh
Jun 14 at 8:55
1
Eek! But also huh.
â Kusalananda
Jun 14 at 10:23
add a comment |Â
up vote
4
down vote
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
fi
by a find
based expression.
if [ "$( find "$file1" -newer "$file2" )" ]; then
echo newer
fi
works at least as long as $file1
does not only contain newlines.
if [ "$( find -L "$file1" -newer "$file2" -exec echo newer ; )" ]; then
echo newer
fi
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 at 8:38
2
I think the downvote is probably about the confrontational wording. Here, it would be fairer to call it a limitation (significant in some contexts). Somefind
implementations like busybox or heirloom-toolchest will have the same limitation.
â Stéphane Chazelas
Jun 14 at 8:45
3
You'd need-L
for the thefind
version to be equivalent to-nt
. It would also fail on file names that start with-
or!
,(
...
â Stéphane Chazelas
Jun 14 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.
â Stéphane Chazelas
Jun 14 at 8:52
1
@schily, yes, BSDsfind
havefind -f "$file"
for that but it's not portable.
â Stéphane Chazelas
Jun 14 at 8:58
 |Â
show 9 more comments
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
8
down vote
accepted
POSIXLY:
f1=/path/to/file_1
f2=/path/to/file_2
if [ -n "$(find -L "$f1" -prune -newer "$f2")" ]; then
printf '%s is newer than %sn' "$f1" "$f2"
fi
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 at 7:28
1
@ilkkachu could be worked around with-exec echo x ;
or similar?
â muru
Jun 14 at 7:33
@muru, yeah.-printf
would be easy if it were standard
â ilkkachu
Jun 14 at 7:36
3
@Kusalananda AFAICT,find
's exit status is independent of what the individual tests offind
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 at 7:46
1
Note that the behaviour of[ / -nt /nofile ]
varies with the implementation (but never outputs any error).
â Stéphane Chazelas
Jun 14 at 9:04
 |Â
show 10 more comments
up vote
8
down vote
accepted
POSIXLY:
f1=/path/to/file_1
f2=/path/to/file_2
if [ -n "$(find -L "$f1" -prune -newer "$f2")" ]; then
printf '%s is newer than %sn' "$f1" "$f2"
fi
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 at 7:28
1
@ilkkachu could be worked around with-exec echo x ;
or similar?
â muru
Jun 14 at 7:33
@muru, yeah.-printf
would be easy if it were standard
â ilkkachu
Jun 14 at 7:36
3
@Kusalananda AFAICT,find
's exit status is independent of what the individual tests offind
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 at 7:46
1
Note that the behaviour of[ / -nt /nofile ]
varies with the implementation (but never outputs any error).
â Stéphane Chazelas
Jun 14 at 9:04
 |Â
show 10 more comments
up vote
8
down vote
accepted
up vote
8
down vote
accepted
POSIXLY:
f1=/path/to/file_1
f2=/path/to/file_2
if [ -n "$(find -L "$f1" -prune -newer "$f2")" ]; then
printf '%s is newer than %sn' "$f1" "$f2"
fi
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 . ;
POSIXLY:
f1=/path/to/file_1
f2=/path/to/file_2
if [ -n "$(find -L "$f1" -prune -newer "$f2")" ]; then
printf '%s is newer than %sn' "$f1" "$f2"
fi
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 . ;
edited Jun 15 at 3:38
answered Jun 14 at 7:20
cuonglm
96.8k21183276
96.8k21183276
technically, I think it fails if$f1
only contains newlines ;)
â ilkkachu
Jun 14 at 7:28
1
@ilkkachu could be worked around with-exec echo x ;
or similar?
â muru
Jun 14 at 7:33
@muru, yeah.-printf
would be easy if it were standard
â ilkkachu
Jun 14 at 7:36
3
@Kusalananda AFAICT,find
's exit status is independent of what the individual tests offind
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 at 7:46
1
Note that the behaviour of[ / -nt /nofile ]
varies with the implementation (but never outputs any error).
â Stéphane Chazelas
Jun 14 at 9:04
 |Â
show 10 more comments
technically, I think it fails if$f1
only contains newlines ;)
â ilkkachu
Jun 14 at 7:28
1
@ilkkachu could be worked around with-exec echo x ;
or similar?
â muru
Jun 14 at 7:33
@muru, yeah.-printf
would be easy if it were standard
â ilkkachu
Jun 14 at 7:36
3
@Kusalananda AFAICT,find
's exit status is independent of what the individual tests offind
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 at 7:46
1
Note that the behaviour of[ / -nt /nofile ]
varies with the implementation (but never outputs any error).
â Stéphane Chazelas
Jun 14 at 9:04
technically, I think it fails if
$f1
only contains newlines ;)â ilkkachu
Jun 14 at 7:28
technically, I think it fails if
$f1
only contains newlines ;)â ilkkachu
Jun 14 at 7:28
1
1
@ilkkachu could be worked around with
-exec echo x ;
or similar?â muru
Jun 14 at 7:33
@ilkkachu could be worked around with
-exec echo x ;
or similar?â muru
Jun 14 at 7:33
@muru, yeah.
-printf
would be easy if it were standardâ ilkkachu
Jun 14 at 7:36
@muru, yeah.
-printf
would be easy if it were standardâ ilkkachu
Jun 14 at 7:36
3
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 at 7:46
@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 at 7:46
1
1
Note that the behaviour of
[ / -nt /nofile ]
varies with the implementation (but never outputs any error).â Stéphane Chazelas
Jun 14 at 9:04
Note that the behaviour of
[ / -nt /nofile ]
varies with the implementation (but never outputs any error).â Stéphane Chazelas
Jun 14 at 9:04
 |Â
show 10 more comments
up vote
7
down vote
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 comparex
and$'xnx'
for instance.
â Stéphane Chazelas
Jun 14 at 8:47
I added those, thanks.
â meuh
Jun 14 at 8:55
1
Eek! But also huh.
â Kusalananda
Jun 14 at 10:23
add a comment |Â
up vote
7
down vote
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 comparex
and$'xnx'
for instance.
â Stéphane Chazelas
Jun 14 at 8:47
I added those, thanks.
â meuh
Jun 14 at 8:55
1
Eek! But also huh.
â Kusalananda
Jun 14 at 10:23
add a comment |Â
up vote
7
down vote
up vote
7
down vote
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.
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.
edited Jun 14 at 8:53
answered Jun 14 at 8:44
meuh
29.2k11648
29.2k11648
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 comparex
and$'xnx'
for instance.
â Stéphane Chazelas
Jun 14 at 8:47
I added those, thanks.
â meuh
Jun 14 at 8:55
1
Eek! But also huh.
â Kusalananda
Jun 14 at 10:23
add a comment |Â
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 comparex
and$'xnx'
for instance.
â Stéphane Chazelas
Jun 14 at 8:47
I added those, thanks.
â meuh
Jun 14 at 8:55
1
Eek! But also huh.
â Kusalananda
Jun 14 at 10:23
3
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 $'xnx'
for instance.â Stéphane Chazelas
Jun 14 at 8:47
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 $'xnx'
for instance.â Stéphane Chazelas
Jun 14 at 8:47
I added those, thanks.
â meuh
Jun 14 at 8:55
I added those, thanks.
â meuh
Jun 14 at 8:55
1
1
Eek! But also huh.
â Kusalananda
Jun 14 at 10:23
Eek! But also huh.
â Kusalananda
Jun 14 at 10:23
add a comment |Â
up vote
4
down vote
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
fi
by a find
based expression.
if [ "$( find "$file1" -newer "$file2" )" ]; then
echo newer
fi
works at least as long as $file1
does not only contain newlines.
if [ "$( find -L "$file1" -newer "$file2" -exec echo newer ; )" ]; then
echo newer
fi
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 at 8:38
2
I think the downvote is probably about the confrontational wording. Here, it would be fairer to call it a limitation (significant in some contexts). Somefind
implementations like busybox or heirloom-toolchest will have the same limitation.
â Stéphane Chazelas
Jun 14 at 8:45
3
You'd need-L
for the thefind
version to be equivalent to-nt
. It would also fail on file names that start with-
or!
,(
...
â Stéphane Chazelas
Jun 14 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.
â Stéphane Chazelas
Jun 14 at 8:52
1
@schily, yes, BSDsfind
havefind -f "$file"
for that but it's not portable.
â Stéphane Chazelas
Jun 14 at 8:58
 |Â
show 9 more comments
up vote
4
down vote
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
fi
by a find
based expression.
if [ "$( find "$file1" -newer "$file2" )" ]; then
echo newer
fi
works at least as long as $file1
does not only contain newlines.
if [ "$( find -L "$file1" -newer "$file2" -exec echo newer ; )" ]; then
echo newer
fi
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 at 8:38
2
I think the downvote is probably about the confrontational wording. Here, it would be fairer to call it a limitation (significant in some contexts). Somefind
implementations like busybox or heirloom-toolchest will have the same limitation.
â Stéphane Chazelas
Jun 14 at 8:45
3
You'd need-L
for the thefind
version to be equivalent to-nt
. It would also fail on file names that start with-
or!
,(
...
â Stéphane Chazelas
Jun 14 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.
â Stéphane Chazelas
Jun 14 at 8:52
1
@schily, yes, BSDsfind
havefind -f "$file"
for that but it's not portable.
â Stéphane Chazelas
Jun 14 at 8:58
 |Â
show 9 more comments
up vote
4
down vote
up vote
4
down vote
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
fi
by a find
based expression.
if [ "$( find "$file1" -newer "$file2" )" ]; then
echo newer
fi
works at least as long as $file1
does not only contain newlines.
if [ "$( find -L "$file1" -newer "$file2" -exec echo newer ; )" ]; then
echo newer
fi
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.
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
fi
by a find
based expression.
if [ "$( find "$file1" -newer "$file2" )" ]; then
echo newer
fi
works at least as long as $file1
does not only contain newlines.
if [ "$( find -L "$file1" -newer "$file2" -exec echo newer ; )" ]; then
echo newer
fi
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.
edited Jun 14 at 9:16
answered Jun 14 at 8:24
schily
8,57421435
8,57421435
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 at 8:38
2
I think the downvote is probably about the confrontational wording. Here, it would be fairer to call it a limitation (significant in some contexts). Somefind
implementations like busybox or heirloom-toolchest will have the same limitation.
â Stéphane Chazelas
Jun 14 at 8:45
3
You'd need-L
for the thefind
version to be equivalent to-nt
. It would also fail on file names that start with-
or!
,(
...
â Stéphane Chazelas
Jun 14 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.
â Stéphane Chazelas
Jun 14 at 8:52
1
@schily, yes, BSDsfind
havefind -f "$file"
for that but it's not portable.
â Stéphane Chazelas
Jun 14 at 8:58
 |Â
show 9 more comments
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 at 8:38
2
I think the downvote is probably about the confrontational wording. Here, it would be fairer to call it a limitation (significant in some contexts). Somefind
implementations like busybox or heirloom-toolchest will have the same limitation.
â Stéphane Chazelas
Jun 14 at 8:45
3
You'd need-L
for the thefind
version to be equivalent to-nt
. It would also fail on file names that start with-
or!
,(
...
â Stéphane Chazelas
Jun 14 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.
â Stéphane Chazelas
Jun 14 at 8:52
1
@schily, yes, BSDsfind
havefind -f "$file"
for that but it's not portable.
â Stéphane Chazelas
Jun 14 at 8:58
1
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 at 8:38
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 at 8:38
2
2
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.â Stéphane Chazelas
Jun 14 at 8:45
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.â Stéphane Chazelas
Jun 14 at 8:45
3
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 !
, (
...â Stéphane Chazelas
Jun 14 at 8:50
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 !
, (
...â Stéphane Chazelas
Jun 14 at 8:50
2
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.
â Stéphane Chazelas
Jun 14 at 8:52
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.
â Stéphane Chazelas
Jun 14 at 8:52
1
1
@schily, yes, BSDs
find
have find -f "$file"
for that but it's not portable.â Stéphane Chazelas
Jun 14 at 8:58
@schily, yes, BSDs
find
have find -f "$file"
for that but it's not portable.â Stéphane Chazelas
Jun 14 at 8:58
 |Â
show 9 more comments
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f449741%2fperforming-nt-ot-test-in-a-posix-sh%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
As you can see in my answer, bash does not implement the
-nt
feature oftest
in a way that is expected since approx. 1995. You should use thefind
basd expression even withbash
if you like correct behavior.â schily
Jun 14 at 8:39