How to use sed to delete timestamp pattern from a zero-terminated list of filenames

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:

find . -maxdepth 1 -type f -printf '%T@ %p\0' | 
    sort -rz | sed -z '1,8d; s/^[^ ]* //'

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:

find . -maxdepth 1 -type f -printf '%T@ %p\0' | 
    sort -rznk1,1 | sed -z '1,8d; s/^[^ ]* //'

Convert the two Sed processes into a single one.

sort -zrn | sed -z "1,8d; s/^[0-9]*\.[0-9]* //"

Corrections applied:

  • Do a numerical 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 that g. 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 from s/^[0-9]*\.[0-9]* //, that deletes the string matching the regex.


You can use your find command with GNU awk:

find . -maxdepth 1 -type f -printf '%T@ %p\0' | sort -zrn | awk 'BEGIN{RS=ORS="\0"} NR>8 {sub(/[^ ]+ /, ""); print}'

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:

$ touch {01..15}.txt
$ ls
01.txt  02.txt  03.txt  04.txt  05.txt  06.txt  07.txt  08.txt  09.txt  10.txt  11.txt  12.txt  13.txt  14.txt  15.txt
$ find . -maxdepth 1 -type f -printf '%T@ %p\0' | sort -zrn | awk 'BEGIN{RS=ORS="\0"} NR>8 {sub(/[^ ]+ /, ""); print}'
./07.txt./06.txt./05.txt./04.txt./03.txt./02.txt./01.txt