Sorted array of files

Hi
It is possible to get sorted array (by name or creation-time) with /file find ?
I need to delete recent n files
Снимок экрана 2021-09-14 162542.png

[admin@MikroTik7-Test] > /file print detail where name~"MikroTik7-Test_.+\\.backup\$" 
 0 name="MikroTik7-Test_2021-09-14_132825.backup" type="backup" size=72.9KiB creation-time=sep/14/2021 13:28:25 
 1 name="MikroTik7-Test_2021-09-14_132104.backup" type="backup" size=72.8KiB creation-time=sep/14/2021 13:21:04 
15 name="MikroTik7-Test_2021-09-14_142900.backup" type="backup" size=72.8KiB creation-time=sep/14/2021 14:29:00 
 3 name="MikroTik7-Test_2021-09-14_132205.backup" type="backup" size=72.8KiB creation-time=sep/14/2021 13:22:05 
 4 name="MikroTik7-Test_2021-09-14_132340.backup" type="backup" size=72.8KiB creation-time=sep/14/2021 13:23:40 
 5 name="MikroTik7-Test_2021-09-14_132455.backup" type="backup" size=72.8KiB creation-time=sep/14/2021 13:24:55 
 7 name="MikroTik7-Test_2021-09-14_133044.backup" type="backup" size=72.8KiB creation-time=sep/14/2021 13:30:44 
 8 name="MikroTik7-Test_2021-09-14_115638.backup" type="backup" size=72.8KiB creation-time=sep/14/2021 11:56:38 
16 name="MikroTik7-Test_2021-09-14_142715.backup" type="backup" size=72.8KiB creation-time=sep/14/2021 14:27:15

# Part of my script
:local bkFilesArr [/file find name~"MikroTik7-Test_.+\\.backup\$"]
:local bkFilesLen [:len $bkFilesArr]
:log info "bak [6.2] backups: $bkFilesLen"
:local i 0
:foreach file in=$bkFilesArr do={
    :log info ("bak [6.3.$i] $file " . [/file get $file name])
    set $i ($i + 1)
}

search tag # rextended hack sort file by date

Based on my scripts:
http://forum.mikrotik.com/t/i-did-it-script-to-compute-unix-time/68576/1

Step 1 [DONE]: convert all backup filenames and date to a 2D array and convert the date from mmm-DD-YYYY to YYYY-MM-DD:
Step 2 [DONE]: sort the array by YYYY-MM-DD using an hack
Step 3 [DONE]: delete the older backups over max “X” allowed

I comment the line when the file is removed for security, the number of max backup allowed is defined on maxbackup variable insidethe script
for sort all file, just remove > where type=“backup”< on find
(compatible also with new date format on RouterOS 7.10+)

/file
{
:local maxbackup 5

:local crtime    ""
:local filename  ""
:local filelist  [:toarray ""]
:foreach file in=[find where type="backup"] do={
    :set crtime  [get $file creation-time]
    :local vdoff [:toarray "0,4,5,7,8,10"]
    :local MM    [:pick $crtime ($vdoff->2) ($vdoff->3)]
    :local M     [:tonum $MM]
    :if ($crtime ~ ".../../....") do={
        :set vdoff [:toarray "7,11,1,3,4,6"]
        :set M     ([:find "xxanebarprayunulugepctovecANEBARPRAYUNULUGEPCTOVEC" [:pick $crtime ($vdoff->2) ($vdoff->3)] -1] / 2)
        :if ($M>12) do={:set M ($M - 12)}
        :set MM    [:pick (100 + $M) 1 3]
    }
    :set crtime   "$[:pick $crtime ($vdoff->0) ($vdoff->1)]-$MM-$[:pick $crtime ($vdoff->4) ($vdoff->5)] $[:pick $crtime 12 20]"
    :set filename [get $file name]
    :set filelist ($filelist, [[:parse ":return {\"$crtime\"=\"$filename\"}"]])
    :put "\"$crtime\"=\"$filename\""
}

:local currentbk [:len $filelist]
:local overbackp ($currentbk - $maxbackup)

:if ($currentbk > $maxbackup) do={
    :foreach x,y in=$filelist do={
        :if ($overbackp > 0) do={
            :log info "There are more than $maxbackup backups, $y deleted"
#           remove [find where name="$y"]
            :set overbackp ($overbackp - 1)
        }
    }
}

}

rextended
Thank you very much for quick reply
This is exactly what i need

Thanks, you let me discovery an hack to sort the array on just 2/3 lines of code :slight_smile:

This Hack is cool) really
Also this work for filenames only, without manipulation with dates

:local bkFilesArr [:toarray ""]
:global bkFilesSortedArr [:toarray ""]

:foreach file in=[/file find name~"MikroTik7-Test_.+\\.backup\$"] do={
    :set bkFilesArr ($bkFilesArr, "\"$[/file get $file name]\"=\"\"")
}
:if ([:len $bkFilesArr] > 0) do={
    [:parse ":global bkFilesSortedArr; :set bkFilesSortedArr {$[:tostr $bkFilesArr]}"]
}

# display
:local i 0
:foreach key,value in=$bkFilesSortedArr do={
    :log info "bak [6.2.$i] $key"
    :set i ($i + 1)
}
:set bkFilesSortedArr

Yes, but speaking about “files” the correct order for determine what is older is the date :wink:
The backup can have any name.

of course
but in this particular case it will work
my files follow a strict template

Is MikroTik7 because you use it on 7.x version?

You can use the function date2ymd also when you do the backup, if the function is shorter than your methods to obtain YYYY-MM-DD

also on backup, if you want automatize name, you can also use $[/sys id get itentity] instead of hardcoded mikrotik7-test name

i use

[/system identity get name]
[/system routerboard get serial-number]

:local bkBackupFilesArr [/file find name~$bkIdentity.$bkSerial."_.+\\".$bkBackupExt."\$"]

I made this for you, just call $dobackup

:global dobackup do={
    /system clock
    :local strDate [get date]; :local strTime [get time]
    :local arrMonths {jan="01";feb="02";mar="03";apr="04";may="05";jun="06";jul="07";aug="08";sep="09";oct="10";nov="11";dec="12"}
    :local intYear [:tonum [:pick $strDate 7 11]]; :local strMonth ($arrMonths->[:pick $strDate 0 3]); :local strDay [:pick $strDate 4 6]
    :local strHour [:pick $strTime 0 2]; :local strMinute [:pick $strTime 3 5]; :local strSecond [:pick $strTime 6 8]
    /system backup save dont-encrypt=yes name="$[/sys id get name]_$intYear-$strMonth-$strDay_$strHour$strMinute$strSecond"
}

Ah, Ok, for coincidence the “7” is a part of serial number censored??? :laughing:

No) I am doing tests on CHR. there is no serial number at all)
but of course I shortened the script code for the forum

There’s more elegant way to sort array using built-in mikrotik array sorting in case of key-value array.
This http://forum.mikrotik.com/t/sorted-array-of-files/151870/1 hack is nice, but we can achieve same result without global tmpsortlist.
Tested on ROS 6 & 7.
My hack idea is in this line:

:set hackSort ($hackSort, [[:parse "[:toarray {\"$ymd\"=\"$filename\"}]"]]);

Also, tempidx is not used anywhere in script, can be safely removed;

Full script:

:global date2ymd do={
 /system clock;
 :local strDate "$1";
 :local arrMonths {jan="01";feb="02";mar="03";apr="04";may="05";jun="06";jul="07";aug="08";sep="09";oct="10";nov="11";dec="12"};
 :local intYear [:tonum [:pick $strDate 7 11]]; :local strMonth ($arrMonths->[:pick $strDate 0 3]); :local strDay [:pick $strDate 4 6];
 :local strHour [:pick $strDate 12 14]; :local strMinute [:pick $strDate 15 17]; :local strSecond [:pick $strDate 18 20];
 :return "$intYear-$strMonth-$strDay $strHour:$strMinute:$strSecond";
}

{
:local maxbackup 5;

:local hackSort [:toarray ""];
/file;
:foreach file in=[find where type="backup"] do={
 :local ymd [$date2ymd [get $file creation-time]];
 :local filename [get $file name];
 :put "YMD data for \"$filename\" is $ymd";
 :set hackSort ($hackSort, [[:parse "[:toarray {\"$ymd\"=\"$filename\"}]"]]);
}

:local currentbk [:len $hackSort];
:local overbackp ($currentbk - $maxbackup);
:foreach x,y in=$hackSort do={
 :put "DATE $x FILE $y";
}
:if ($currentbk>$maxbackup) do={
 :put "$overbackp more Backups than desired";
}
:foreach x,y in=$hackSort do={
 :if ($overbackp > 0) do={
  :put "DELETE $x FILE $y";
# remove [find where name="$y"]
  :set overbackp ($overbackp - 1);
 }
}
}

Also /system clock and other frills can be removed, syntax refreshed, etc…

fixed main post

Thank you, I used this technique to remove aging files (used to update APs).

Now some files have the exact same date/time information and this doesn’t work.
Is there a better way to achieve the same thing in 2024 ? :slight_smile:

Thank you