Those patches look good to me. Here are two follow-ups.
The first updates the docs to mention the equal-timestamps pitfall. The
second tweaks some of the shell code examples (quoting, among other things).
From 79c38669d1bff076a7f2bc567addc88093725b3e Mon Sep 17 00:00:00 2001
From: James Youngman <[email protected]>
Date: Tue, 14 Oct 2025 19:50:29 +0100
Subject: [PATCH 1/2] find: point out that -newer is false when timestamps are
equal.
---
doc/find.texi | 15 ++++++++++-----
find/find.1 | 14 ++++++++++++--
2 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/doc/find.texi b/doc/find.texi
index 3d7c63a1..0892f3d6 100644
--- a/doc/find.texi
+++ b/doc/find.texi
@@ -1036,8 +1036,9 @@ command line.
@deffn Test -newerXY reference
Succeeds if timestamp @samp{X} of the file being considered is newer
-than timestamp @samp{Y} of the file @file{reference}. The letters
-@samp{X} and @samp{Y} can be any of the following letters:
+than timestamp @samp{Y} of the file @file{reference}.
+Fails if the timestamps are @emph{equal}.
+The letters @samp{X} and @samp{Y} can be any of the following letters:
@table @samp
@item a
@@ -1077,7 +1078,8 @@ not UFS1 file systems.
There are two ways to list files in @file{/usr} modified after
-February 1 of the current year. One uses @samp{-newermt}:
+@emph{the start} of February 1 of the current year. One uses
+@samp{-newermt}:
@example
find /usr -newermt "Feb 1"
@@ -1098,6 +1100,7 @@ rm -f /tmp/stamp$$
True if the time of the last access (or status change or data modification)
of the current file is more recent than that of the last data modification
of the @var{reference} file.
+False if the timestamps are equal.
As such, @samp{-anewer} is equivalent to @samp{-neweram},
@samp{-cnewer} to @samp{-newercm}, and @samp{-newer} to @samp{-newermm}.
@@ -5059,7 +5062,8 @@ find subdir -newer timestamp -and \
@end smallexample
Here, the @samp{-newer} test excludes all the files which are
-definitely older than the timestamp, but all the files which are newer
+definitely older than or the same age as
+the timestamp, but all the files which are newer
than the old value of the timestamp are compared against the current
updated timestamp.
@@ -5132,7 +5136,8 @@ find subdir -newer timestamp -printf "%A@@:%p\0" |
@end smallexample
The first @code{find} command generates a list of files which are
-newer than the original timestamp file, and prints a list of them with
+newer than (and not the same age as) the original timestamp file,
+and prints a list of them with
their timestamps. The @file{newest.pl} script simply filters out all
the filenames which have timestamps which are older than whatever the
newest file is:
diff --git a/find/find.1 b/find/find.1
index 27c3316b..a51a2f4b 100644
--- a/find/find.1
+++ b/find/find.1
@@ -716,6 +716,8 @@ Like
.BR \-newer ,
but test if the time of the last access of the current file is more recent than
that of the last data modification of the \fIreference\fR file.
+Fails if the timestamps are
+.BR equal .
If \fIreference\fR is a symbolic link and the
.B \-H
option or the
@@ -745,6 +747,8 @@ Like
.BR \-newer ,
but test if the time of the last status change of the current file is more
recent than that of the last data modification of the \fIreference\fR file.
+Fails if the timestamps are
+.BR equal .
If \fIreference\fR is a symbolic link and the
.B \-H
option or the
@@ -905,8 +909,11 @@ Don't forget to enclose the pattern in quotes in order to protect it
from expansion by the shell.
.IP "\-newer \fIreference\fR"
-Time of the last data modification of the current file is more recent than that
+Succeeds if the
+time of the last data modification of the current file is more recent than that
of the last data modification of the \fIreference\fR file.
+Fails if the timestamps are
+.BR equal .
If \fIreference\fR is a symbolic link and the
.B \-H
option or the
@@ -916,8 +923,11 @@ it points to is always used.
.IP "\-newerXY \fIreference\fR"
Succeeds if timestamp \fIX\fR of the file being considered is newer
-than timestamp \fIY\fR of the file
+than
+the timestamp \fIY\fR of the file
.IR reference .
+Fails if the timestamps are
+.BR equal .
The letters \fIX\fR and \fIY\fR can be any of the following letters:
.TS
--
2.39.5
From 87a34fa37070bb95e235145f958dbdefe5232f3c Mon Sep 17 00:00:00 2001
From: James Youngman <[email protected]>
Date: Tue, 14 Oct 2025 20:17:12 +0100
Subject: [PATCH 2/2] doc: minor shell coding improvements in examples.
- Use -type f so that the timestamp of `subdir` is not relevant.
- Use LC_ALL=C with sort, tail, cut (as file names are not text).
- Use "$(...)" instead of just $(...).
Also mention that Issue 8 of the POSIX standard has been published
now.
---
doc/find.texi | 38 ++++++++++++++++++++------------------
1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/doc/find.texi b/doc/find.texi
index 0892f3d6..581807d7 100644
--- a/doc/find.texi
+++ b/doc/find.texi
@@ -4680,6 +4680,9 @@ there are lots of files to delete. Since the task is to delete
unwanted files, this is precisely the time we don't want things to go
wrong.
+There is also a second problem with this method. We will discuss that
+below.
+
@subsection Making Use of @code{xargs}
So, is there a way to be more efficient in the use of @code{fork()}
@@ -4753,8 +4756,7 @@ portable construct. Support for @samp{-print0} is not universal.
Although some other versions of Unix (notably BSD-derived ones)
support @samp{-print0}, this is only required in POSIX from Issue 8
-(which as of 2024-06-03 has not yet been published). So, is there a
-more universal mechanism?
+(published 2024-06-14). So, is there a more universal mechanism?
@subsection Going back to @code{-exec}
@@ -5021,7 +5023,7 @@ different ways to do it.
The obvious but wrong answer is just to use @samp{-newer}:
@smallexample
-find subdir -newer timestamp -exec touch -r @{@} timestamp \;
+find subdir -type f -newer timestamp -exec touch -r @{@} timestamp \;
@end smallexample
This does the right sort of thing but has a bug. Suppose that two
@@ -5042,7 +5044,7 @@ compared against it, but that will reduce the performance of
The @code{test} command can be used to compare timestamps:
@smallexample
-find subdir -exec test @{@} -nt timestamp \; -exec touch -r @{@} timestamp \;
+find subdir -type f -exec test @{@} -nt timestamp \; -exec touch -r @{@} timestamp \;
@end smallexample
This will ensure that any changes made to the modification time of
@@ -5056,7 +5058,7 @@ We can of course still use @samp{-newer} to cut down on the number of
calls to @code{test}:
@smallexample
-find subdir -newer timestamp -and \
+find subdir -type f -newer timestamp -and \
-exec test @{@} -nt timestamp \; -and \
-exec touch -r @{@} timestamp \;
@end smallexample
@@ -5076,10 +5078,8 @@ It is possible to use the @samp{-printf} action to abandon the use of
@code{test} entirely:
@smallexample
-newest=$(find subdir -newer timestamp -printf "%A@@:%p\n" |
- sort -n |
- tail -n1 |
- cut -d: -f2- )
+newest="$(find subdir -type f -newer timestamp -printf "%A@@:%p\n" |
+ env LC_ALL=C sh -c 'sort -n | tail -n1 | cut -d: -f2-' )"
touch -r "$@{newest:-timestamp@}" timestamp
@end smallexample
@@ -5087,19 +5087,20 @@ The command above works by generating a list of the timestamps and
names of all the files which are newer than the timestamp. The
@code{sort}, @code{tail} and @code{cut} commands simply pull out the
name of the file with the largest timestamp value (that is, the latest
-file). The @code{touch} command is then used to update the timestamp,
+file). We run those programs (which normally read and write text)
+with with the @env{LC_ALL} environment variable set to @samp{C} in
+order to avoid character encoding problems; file names are not
+guaranteed to have a valid (or consistent) character encoding. The
+@code{touch} command is then used to update the timestamp,
The @code{"$@{newest:-timestamp@}"} expression simply expands to the
value of @code{$newest} if that variable is set, but to
@file{timestamp} otherwise. This ensures that an argument is always
given to the @samp{-r} option of the @code{touch} command.
-This approach seems quite efficient, but unfortunately it has a
-problem. Many operating systems now keep file modification time
-information at a granularity which is finer than one second.
-Findutils version 4.3.3 and later will print a fractional part with
-%A@@, but older versions will not.
-
+@c We used to warn the reader about older versions of Find where %A@
+@c didn't include a fractional part, but since Findutils 4.3.3 was
+@c released in 2007, people are unlikely to have a problem today.
@subsection Solving the problem with @code{make}
@@ -5108,8 +5109,9 @@ use @code{find} to generate a @file{Makefile} file on the fly and then
use @code{make} to update the timestamps:
@smallexample
-makefile=$(mktemp)
+makefile="$(mktemp)"
find subdir \
+ -type f \
\( \! -xtype l \) \
-newer timestamp \
-printf "timestamp:: %p\n\ttouch -r %p timestamp\n\n" > "$makefile"
@@ -5129,7 +5131,7 @@ space), and do things more efficiently too. The following command
works with newlines and doesn't need to sort the list of filenames.
@smallexample
-find subdir -newer timestamp -printf "%A@@:%p\0" |
+find subdir -type f -newer timestamp -printf "%A@@:%p\0" |
perl -0 newest.pl |
xargs --no-run-if-empty --null --replace \
find @{@} -maxdepth 0 -newer timestamp -exec touch -r @{@} timestamp \;
--
2.39.5