Re: find -newermt YYYY-MM-DD does not match midnight.
James Youngman <[email protected]> Tue, 14 Oct 2025 20:23:20 +0100
| Newsgroups | gmane.comp.gnu.findutils.bugs |
|---|---|
| Message-ID | <CAGwX76525k3Co8=O1vraG3GpVNMssGpoKz7Y_J-5dmLMWt=2yQ@mail.gmail.com> |
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).
0001-find-point-out-that-newer-is-false-when-timestamps-a.patch
(text/x-patch, 4 KB)
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
0002-doc-minor-shell-coding-improvements-in-examples.patch
(text/x-patch, 5.2 KB)
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