Community discussions

MikroTik App
 
tomislav91
Member
Member
Topic Author
Posts: 313
Joined: Fri May 26, 2017 12:47 pm

modify files inside mikrotik

Thu Oct 03, 2024 4:55 pm

So,

is it possible to modify a files which are uploaded into Files in mikrotik routers via cli? I need to change some link inside it.
I can access it via
file edit value-name=contents test.txt
but how to change it there through terminal
 
User avatar
normis
MikroTik Support
MikroTik Support
Posts: 27060
Joined: Fri May 28, 2004 11:04 am
Location: Riga, Latvia
Contact:

Re: modify files inside mikrotik

Thu Oct 03, 2024 5:27 pm

you already wrote the command to do it from terminal. what is the issue with this command?
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 4701
Joined: Sun May 01, 2016 7:12 pm
Location: California
Contact:

Re: modify files inside mikrotik

Fri Oct 04, 2024 6:57 am

is it possible to modify a files which are uploaded into Files in mikrotik routers via cli? I need to change some link inside it.
I can access edit it via
file edit value-name=contents test.txt
but how to change set it there through terminal

/file set test.txt contents="Did you want to write stuff at the CLI prompt?" 
 
tomislav91
Member
Member
Topic Author
Posts: 313
Joined: Fri May 26, 2017 12:47 pm

Re: modify files inside mikrotik

Fri Oct 04, 2024 9:18 am

No, i have a file name test.txt and in that file I need to change some url, so instead of http to use https, thats the only change.
But i cannot fetch it again, cause every file is different
 
User avatar
normis
MikroTik Support
MikroTik Support
Posts: 27060
Joined: Fri May 28, 2004 11:04 am
Location: Riga, Latvia
Contact:

Re: modify files inside mikrotik

Fri Oct 04, 2024 9:28 am

Sorry, still not understanding your issue.

issue command "file edit value-name=contents test.txt" and change your URL. what's the problem?
 
tomislav91
Member
Member
Topic Author
Posts: 313
Joined: Fri May 26, 2017 12:47 pm

Re: modify files inside mikrotik

Fri Oct 04, 2024 9:31 am

problem is that i have more than 1000 routers, and dont wanna do it manualy, so i will use automation to do it, and thats why i need a single command.
 
User avatar
normis
MikroTik Support
MikroTik Support
Posts: 27060
Joined: Fri May 28, 2004 11:04 am
Location: Riga, Latvia
Contact:

Re: modify files inside mikrotik

Fri Oct 04, 2024 9:36 am

There is no way to do it in the router. You need a utility like "sed".
 
tomislav91
Member
Member
Topic Author
Posts: 313
Joined: Fri May 26, 2017 12:47 pm

Re: modify files inside mikrotik

Fri Oct 04, 2024 9:41 am

so its not possible something like this thread:
viewtopic.php?t=62024
 
User avatar
normis
MikroTik Support
MikroTik Support
Posts: 27060
Joined: Fri May 28, 2004 11:04 am
Location: Riga, Latvia
Contact:

Re: modify files inside mikrotik

Fri Oct 04, 2024 9:44 am

Did you read the thread? The person answers the same thing as I answered now. You can't do it. RouterOS has no sed utility. You can only overwrite the whole file with new content. All of it.
 
tomislav91
Member
Member
Topic Author
Posts: 313
Joined: Fri May 26, 2017 12:47 pm

Re: modify files inside mikrotik

Tue Oct 08, 2024 8:46 pm

yes i did, but i thought its possible to change it. So, any ideas?
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 4701
Joined: Sun May 01, 2016 7:12 pm
Location: California
Contact:

Re: modify files inside mikrotik

Tue Oct 08, 2024 10:05 pm

Well you would not be the first to want such a function... see 2018 thread: viewtopic.php?t=131692&hilit=regex+sed#p646804
yes i did, but i thought its possible to change it. So, any ideas?
It's not easy, and limited. But you can :find and :pick your way through it... see viewtopic.php?t=192932#p979819
 
tomislav91
Member
Member
Topic Author
Posts: 313
Joined: Fri May 26, 2017 12:47 pm

Re: modify files inside mikrotik

Thu Oct 10, 2024 3:42 pm

i somehow stuck here
/file get test.html contents

/file set test.html contents=[/file get test.html contents; :find "http://"; :pick replace with "https://"]
but there is no replace....of course.. :oops:
 
User avatar
infabo
Forum Guru
Forum Guru
Posts: 1656
Joined: Thu Nov 12, 2020 12:07 pm

Re: modify files inside mikrotik

Thu Oct 10, 2024 4:25 pm

Download file, replace locally with e.g. sed, re-upload file. Can be scripted using REST API for example. Is there anything that hinders you following this approach? APIs not accessible and it must be done locally as a ROS script?
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 4701
Joined: Sun May 01, 2016 7:12 pm
Location: California
Contact:

Re: modify files inside mikrotik

Thu Oct 10, 2024 4:43 pm

i somehow stuck here
/file get test.html contents

/file set test.html contents=[/file get test.html contents; :find "http://"; :pick replace with "https://"]
but there is no replace....of course.. :oops:
The reason why @normis suggested RouterOS is missing `sed` is that it's a lot of script code just to parse it. But I dug up a function that does it, at least in SOME cases. This one is borrowed from @merlinthemagic7 larger script library that I made into a simple function so it not require the rest of MTM's library. I have not test in a while, but seem to still work.

While the function below seems to have held up in the test of time... these large function do introduce risk if you don't know how they work. And if some future RouterOS changing script in certain way, it's possible it will break. Why others, and me, really suggest doing your string parsing elsewhere i.e. before the file copy to router – RouterOS does NOT have primitives for string manipulation, as @normis notes several times.

So if you include this script before you need to do a replacement, then you you can some a more simple like:
:put [$STR replace "http://srv1/,http://srv2" "http://" "https://"]
# https://srv1/,https://srv2
to do the replacement.

Here is the $STR function which support "trim", "split", and "replace" as operations:
### $STR - string helpers 
# from: https://raw.githubusercontent.com/merlinthemagic/MTM-RouterOS-Scripting/main/src/flash/MTM/Tools/Strings/Part1.rsc
:global STR
:set STR do={
    :if ($1="trim") do={
        :local param1
        :if ([:typeof $2] != nil) do={
            :set param1 $2;
        } else={
            :if ([:typeof $str] != nil) do={
                :set param1 $str
            }
            :error "String is mandatory";
        }
        :set param1 [:tostr $param1]; #ROS casts lots of things as arrays. e.g. rx/tx data from interfaces
        :local rLen [:len $param1];
        :local rData "";
        :local ch "";
        :local isDone 0;
        # remove leading spaces
        :for x from=0 to=($rLen - 1) do={
            :set ch [:pick $param1 $x];
            :if ($isDone = 0 && $ch != " " && $ch != "\n" && $ch != "\r") do={
                :set rData [:pick $param1 $x $rLen];
                :set isDone 1;
            }
        }
        :set rLen [:len $rData];
        :local cPos $rLen;
        :set isDone 0;
        # remove trailing spaces
        :for x from=1 to=($rLen - 1) do={
            :set cPos ($rLen - $x);
            :set ch [:pick $rData $cPos];
            :if ($isDone = 0 && $ch != " " && $ch != "\n" && $ch != "\r") do={
                :set rData [:pick $rData 0 ($cPos + 1)];
                :set isDone 1;
            }
        }
        :if ($rData = [:nothing]) do={
            #always return string, the nil value is a pain
            :set rData "";
        }
        :return $rData;
    }
    :if ($1="replace") do={
        
        :local param1; #str
        :local param2; ##find
        :local param3; ##replace
        :if ([:typeof $1] != nil) do={
            :set param1 $2;
            :set param2 $3;
            :set param3 $4;
        } else={
            :if ([:typeof $str] != nil) do={
                :set param1 $str;
                :set param2 $find;
                :set param3 $replace;
            } else={
                :error "String is mandatory";
            }
        }
        
        :set param1 [:tostr $param1]; #ROS casts lots of things as arrays. e.g. rx/tx data from interfaces
        :local rData "";
        :local pos;
        :local rLen [:len $param1];
        
        :local findLen [:len $param2];
        :local isDone 0;
        :while ($isDone = 0) do={
            :set pos [:find $param1 $param2];
            :if ([:typeof $pos] = "num") do={
                :set rData ($rData.[:pick $param1 0 $pos].$param3);
                :set param1 [:pick $param1 ($pos + $findLen) $rLen];
                :set rLen [:len $param1];
            } else={
                :set rData ($rData.$param1);
                :set isDone 1;
            }
        }
        :return $rData;
    }
    :if ($1="split") do={
        :local param1; #input
        :local param2; #deliminator
        :if ([:typeof $2] != nil) do={
            :set param1 $2;
            #delemitor= case ...
            :set param2 $3;
        } else={
            :if ([:typeof $str] != nil) do={
                :set param1 $str;
                :set param2 $delimitor;
            } else={
                :error "String is mandatory";
            }
        }

        :local rData [:toarray ""];
        :local rCount 0;
        :local splitLen [:len $param2];
        :if ($splitLen = 0) do={
            :set ($rData->$rCount) $param1;
            :return $rData;
        }
        :local lData "";
        :local rLen [:len $param1];
        :local pos;
        :local isDone 0;
        :while ($isDone = 0) do={
            :set pos [:find $param1 $param2];
            :if ([:typeof $pos] = "num") do={
                :set lData [:pick $param1 0 $pos];
                :set param1 [:pick $param1 ($pos + $splitLen) $rLen];
                :set rLen [:len $param1];
            } else={
                :set lData $param1;
                :set isDone 1;
            }
            :set ($rData->$rCount) $lData;
            :set rCount ($rCount + 1);
        }
        :return $rData;
    }
}
You can cut-and-paste that at CLI to test. And then use:
:global replacedContent [$STR replace [/file get FILENAME contents] "http://" "https://"]
# to see the output
:put $replacedContent
# to save output to a new file
/file add name=NEWFILENAME
/file set NEWFILENAME contents=$replacedContent
# if it wanted same file  - which is bad for testing - don't need the /file add
# /file set FILENAME contents=$replacedContent