To find files older than the newest 8 I'm using:
find . -maxdepth 1 -type f -printf '%T@ %p\0' | sort -rz | sed -z 1,8d
The -printf '%T@ %p\0'
command applies a last modified timestamp (expressed as number of seconds since Jan. 1, 1970, 00:00 GMT, with fractional part) to the beginning of each zero-terminated filename matched, something like:
1597765267.7628475560 ./fileName2.txt1597765264.0267179360 ./fileName1.txt
In order to delete these oldest files by piping to xargs -0 gio trash
, I need to remove the timestamps. So I add another sed command to do this:
find . -maxdepth 1 -type f -printf '%T@ %p\0' | sort -rz | sed -z 1,8d | sed -z "s/^[0-9]*.[0-9]* //g"
Now I have the correct output, but is there a better more efficient way?
Based on @Quasímodo's answer, I tried to simplify further by using the sed delete pattern format (as I'm not actually substituting anything), but I got no output:
find . -maxdepth 1 -type f -printf '%T@ %p\0' | sort -rnz | sed -z "1,8d; /^[0-9]*\.[0-9]* /d"
Any suggestions appreciated.
Conclusion (from multiple responses):
find $targetPath -maxdepth 1 -type f -printf '%T@ %p\0' | sort -rnz | sed -z "1,${retain}d; s/^[^ ]* //"
Where:
$targetPath, Directory to find files, e.g. current directory '.'
${retain}, Number of newest files to retain, e.g. 8
Since you control the output, it is very easy to remove the timestamps. You know that each
\0
-delineated record will start with the timestamp and then a space. So all you need to do is remove all non-space characters until the first space:However, you probably want numeric sort and you may as well only sort on the first field, no need to also sort on the file name. So, this will give you the 8 oldest files:
Convert the two Sed processes into a single one.
Corrections applied:
n
umerical Sort..
matches any character, it should be\.
in the regular expression.g
substitutes all matches in a record. You only need a single substitution (namely, removing the time stamp) from each record, so remove thatg
. This modification also improves performance.Your attempt
sed -z "1,8d; /^[0-9]*\.[0-9]* /d"
fails because/^[0-9]*\.[0-9]* /d
deletes every line matching the regex. This is different froms/^[0-9]*\.[0-9]* //
, that deletes the string matching the regex.You can use your
find
command with GNUawk
:Here:
We set the input record separator (
RS
) and the output record separator (ORS
) to\0
.For each record from the 8th record onwards (
NR>8
), we replace everything up to the first space, including the first space, with an empty string (sub(/[^ ]+ /, "")
) and print the record (print
). Thanks @Quasimodo for suggesting improvements on the above command.Example: