Lua Script Basics

Next, in a slightly more useful example, let’s study about a script to ping a specified IP address and record the results in a log.

Here, let’s assume that the scripts indicated as examples are all saved as executable files.

Execute a router command

With the Lua script function, the rt.command function to execute normal router commands from script is provided as a library. Thus, you can execute a ping by calling the pingrouter command using the rt.command function.

[Ping1.lua] Download

flag, outputs = rt.command("ping -c 1 192.168.100.100")
if flag then
  first_line = string.match(outputs, "^(.-)\n")
  print(first_line)
end
# lua /lua/ping1.lua
received from 192.168.100.100: icmp_seq=0 ttl=63 time=1.288ms

How was that? Were you able to ping? When it is not possible to reach the destination IP address, nothing is displayed, so in that case rewrite the address to the IP address that is reachable for “192.168.100.100” and try again.

Now, we will explain the script. First, the first line executes the router’s ping command.

flag, outputs = rt.command("ping -c 1 192.168.100.100")

The rt.command function interprets a string given as an argument as a router command and executes it. Additionally, the rt.command function returns 2 values as return values. The first return value shows that the string is properly interpreted as a command and whether or not the command was executed. The second return value is the command output result or an error message. In this example, they are respectively assigned to flag and outputs variables.

In line 2, the value of the flag variable in the if statement is examined.

if flag then

In an if statement, when the value of the formula between if and then is true, the statements in the interval between then and end are executed. The expression in this example is merely a flag so it becomes an execution result of the rt.command function, and if the format of the command is proper and the command is executed, it will be true.

In the 3rd line, just the first line of the output results of the ping command is extracted.

first_line = string.match(outputs, "^(.-)\n")

In the outputs variable, all the output results of the ping command are included as a string, so, in order to extract only the first line from there, the string.match function is used. Then, the extracted result is substituted for the first_line variable.

For specifics of use of the string.match function, you should look at the Library Function Explanation, with the understanding here that if you write it as per this example the first line will be extracted.

The results are displayed in the 4th line.

print(first_line)

Results are displayed using the print function. You can simply display such character strings using the print function.

The 5th line from the end is an end statement that displays the end of the if statement on the 2nd line.

end

Use of command arguments

With this script, the party to “ping” is fixed at “192.168.100.100”. Next, let’s try making it possible to specify the IP address when executing lua command.

[ping2.lua] download

dst = arg[1]
flag, outputs = rt.command("ping -c 1 " .. dst)
if flag then
  first_line = string.match(outputs, "^(.-)\n")
  print(first_line)
end
# lua /lua/ping2.lua 192.168.100.200
received from 192.168.100.200: icmp_seq=0 ttl=63 time=1.288ms

With “ping2.lua,” we made it possible to designate the IP address by an argument when running a script with the lua command. In the first line of the script, the 1st argument is substituted for the variable dst.

dst = arg[1]

“arg” is a variable that expresses the argument specified by the command, and arg[1] is the first argument, arg[2] is the second argument and arg[N] becomes the Nth argument.

The 2nd line executes the “ping” command.

flag, outputs = rt.command("ping -c 1 " .. dst)

Compared to “ping1.lua,” the argument given to the rt.command function is changed. The string called " ping -c 1 “ and variable dst are concatenated with the .. signal and become one string.

The symbol ..is called a “string concatenation operator,” and this symbol can form a single string by concatenating two strings, before and after it.

The third line and lines thereafter are exactly the same as for “ping1.lua.”

if~then~else

So, for “ping2.lua,” the designation of the correct IP address for the argument of the lua command is a condition, but if the wrong argument is given as the IP address, what will happen?

# lua /lua/ping2.lua 192.168.100.2000

Nothing will be displayed, will it? This is because the rt.command function, which is executing the “ping” command, has failed due to a grammatical error. So, even in that case, let’s try displaying something.

[ping3.lua] download

dst = arg[1]
flag, outputs = rt.command("ping -c 1 " .. dst)
if flag then
  first_line = string.match(outputs, "^(.-)\n")
  print(first_line)
else
  print("ERROR: ping -c 1 " .. dst)
end

Ok, how was it this time?

# lua /lua/ping3.lua 192.168.100.2000
ERROR: ping -c 1 192.168.100.2000

An error string was displayed, wasn’t it? In “ping3.lua”, the else section from the 6th line and 7th line are added to “ping2.lua”.

if flag then
  first_line = string.match(outputs, "^(.-)\n")
  print(first_line)
else
  print("ERROR: ping -c 1 " .. dst)
end

In an if statement, when the value in the value of the formula between if and then is true, the statement after then is executed. Additionally, statements after else are executed when the value of the formula is false. This time the “ping” is a grammatical error, and because the flag, which is the rt.command function return value, is false, the if statement executes the else section and displays the error message.

Function definition and call

Only one IP address could be specified with “ping3.lua” on the command line. Next, let’s set it to ping multiple parties.

[ping4.lua] download

function ping(dst)
  flag, outputs = rt.command("ping -c 1 " .. dst)
  if flag then
    first_line = string.match(outputs, "^(.-)\n")
    return first_line
  else
    return "ERROR: ping -c 1 " .. dst
  end
end

for i = 1, #arg do
  print(ping(arg[i]))
end

So, let's try executing “ping4.lua.”

# lua /lua/ping4.lua 192.168.100.200 192.168.100.201 192.168.100.202
received from 192.168.100.200: icmp_seq=0 ttl=63 time=1.288ms
received from 192.168.100.201: icmp_seq=0 ttl=63 time=1.563ms
received from 192.168.100.202: icmp_seq=0 ttl=63 time=1.435ms

In “ping4.lua,” almost the same thing as “ping3.lua” is enclosed by the function ping(dst)~end. In this way, a chunk of code enclosed by function~end is called a “function.” In this case, the name ping is attached to the function, and afterward when this name is used to call the function, this chunk of code can be executed.

After a function has been defined with function~end it can be called at any time. The relationship between the function definition and the function call in “ping4.lua” is as follows.

-- variable definition
function ping(dst) flag, outputs = rt.command("ping -c 1 " .. dst) if flag then first_line = string.match(outputs, "^(.-)\n") return first_line else return "ERROR: ping -c 1 " .. dst end end
for i = 1, #arg do print(ping(arg[i])) -- function call end

In a function call arg[i] is passed as a real argument to the ping function. The value of arg[i] is substituted for the provisional argument dst in the function definition and the function is executed.

arg[i] and dst are completely different variables, and this is an operation in which, before the function starts to execute, the value of arg[i] is merely substituted for dst. For this reason, during execution of the function, even if the value of dst is changed, there is no change in arg[i] on the function call side.

If there is a return statement in the function definition, then processing returns to the side that called the function. At such time, the formula value continued after the return is passed to the call side as a function value. With ping4.lua, for both success and failure, ping returns a string as a return value, and at the call side this is output as print.

There are several reasons for defining a code chunk as a function. One reason is that when the same process appears many times, that will be defined as a function and called when necessary. By collecting the same process in one place, it becomes clear that the same process is occurring, and when change is necessary, the changed places may be reduced.

Another reason is to give a name to the process and clarify the meaning. In this example, the code that runs “ping” is given the name ping. Due to this, when this function is used later, it becomes possible to clearly understand that “ping” is running.

Combining processes in a suitable unit as a function is very useful when explaining code to people, and afterward when code must be maintained. Let’s use functions actively.

Loops

With ping4.lua in order to process multiple IP addresses passed by the command line, loops with for statements are used. The relevant parts are extracted as follows.

for i = 1, #arg do
  print(ping(arg[i]))
end

In this for statement, while increasing the value of the variable i from 1 to #arg one by one, between do ~end, that is, print(ping(arg[i])) is executed. # means a length operator that returns the size of the array and the length of the string, and #arg represents the size of the arg array, so in this for statement, in the order of the IP addresses given at the command line, the function ping is called and its return value is output.

In this way, as statements for repeated execution, other than the for statement, there are the while statement and the repeat-until statement. When writing code with the same meaning as a for statement, a while statement and a repeat-until statement, the results will be as follows:

for i = 1, #arg do
  print(ping(arg[i]))
end
i = 1
while i <= #arg do
  print(ping(arg[i]))
  i = i + 1
end
if #arg > 0 then
  i = 1
  repeat
    print(ping(arg[i]))
    i = i + 1
  until i > #arg
end

In the while statement, the block is executed while each conditional formula is fulfilled, and in the repeat-until statement, the block is executed as long as each conditional formula is unfulfilled. As the conditional formula is checked after execution of the block for the repeat-until statement, the block will be executed without fail at least once. Thus, in the example above, it is configured so that when the whole is enclosed by an if statement and when the #arg is 0, that is, if no argument is given to the command, the repeat-until statement is not executed.

Although for statements, while statements and repeat-until sentences are sentences that can be repeated in the same way, there are situations that are suitable for use of the respective sentences, so use the appropriate repeating sentence.

Return to Top