Contents:
- Straightforward system() Function
- Reading Output with ipcBeginProcess()
- Using ipcBeginProcess() with Handlers
- Conclusion
Running External Tools via SKILL
When working with a programming language, we should stick to it as much as possible for consistency, efficiency, integration, error handling, scalability, and more.
However, no language can do everything, including SKILL. For tasks like file management (copy, permissions) or working with Excel files, using terminal commands to call external tools is invaluable.
In this guide, we'll explore various ways to use terminal commands via SKILL to run external tasks.
1. Straightforward system() Function
The system() function in SKILL is used to execute external commands or programs from within a SKILL script. This function allows you to interact with the operating system and run shell commands directly, which can be useful for automating tasks, integrating external tools, or manipulating files outside the Virtuoso environment.
Let’s see how to copy a file:
1let( (filePath destinationPath command exitCode)
2 filePath = "./myfile"
3 destinationPath = "./new_file"
4 sprintf(command "cp %s %s" filePath destinationPath)
5
6 exitCode = system(command)
7 if( exitCode == 0
8 then
9 printf("Succeeded to copy file\n")
10 else
11 printf("Failed to copy file\n")
12 );if
13);let
Here, we use Lunix’s “cp” command. You can also run an external script/tool (Bash, Perl, Python) by providing its full path:
1let( (scriptFile command exitCode)
2 scriptFile = "/tmp/myScript.sh"
3 sprintf(command "sh %s" scriptFile)
4
5 exitCode = system(command)
6 if( exitCode == 0
7 then
8 printf("Succeeded to run the script\n")
9 else
10 printf("Failed to run the script\n")
11 );if
12);let
This function is best for short tasks, as it freezes the Virtuoso session until the command is finished. Note that you can't read output when using this function.
2. Reading Output with ipcBeginProcess()
The ipcBeginProcess function in SKILL is part of the Inter-Process Communication (IPC) suite of functions, which allows SKILL scripts to interact with external processes in a more controlled and interactive manner than the system() function. This is particularly useful for applications where you need to start a process, send data to it, and receive data from it, enabling more complex integrations with external tools.
Let’s see how to read an output from a terminal command:
1let( (command process output nextLine)
2 command = "find . -name '*.txt'"
3 process = ipcBeginProcess(command)
4 ipcWait(process)
5
6 output = ""
7 while( nextLine = ipcReadProcess(process)
8 output = strcat(output nextLine)
9 );while
10
11 printf("%s\n" output)
12);let
Here, ipcBeginProcess() creates a subprocess to run the command. We wait for it to finish with ipcWait() and read its buffered output with ipcReadProcess(). The while loop is necessary because ipcReadProcess() reads output from the buffer, not all at once.
Using the function this way is still best for short tasks, as waiting for the process to finish freezes the Virtuoso session. However, now we know how to read commands’ output.
3. Using ipcBeginProcess() with Handlers
The ipcBeginProcess function can provide much more. We can use handlers to run long tasks and read their output, without freezing the Virtuoso session.
In the previous section, we used the command without additional options, which are:
- Host name - Basically, where to run the command. Usually, we will run commands locally, by providing an empty string (“”).
- Data and error handlers - Functions to handle received data from stdout and stderr pipes, useful for reading output and error checking.
- Post or exit handler - Function called when the subprocess terminates, useful for post-processing and error handling.
- Log file - Path to a log file where all output will be saved.
Let’s look at the next example. We’ll run the “find” command from previous example, using the additional options:
1let( (command)
2 command = "find . -name '*.txt'"
3 ipcBeginProcess(
4 command
5 "" ; Local
6 'readData
7 'readError
8 'exitHandler
9 )
10);let
11
12procedure( readData(childId data)
13 ; Do data handling stuff here
14 printf("Process: %d\nOutput:\n%s\n" childId data)
15);procedure
16
17procedure( readError(childId data)
18 ; Do error handling stuff here
19 printf("Process: %d\nOutput:\n%s\n" childId data)
20);procedure
21
22procedure( exitHandler(childId exitStatus)
23 ; Do post processing stuff here
24 printf("Process %d finished with code %d\n" childId exitStatus)
25);procedure
In this example, the Virtuoso session remains responsive, allowing you to continue working while the process runs. The buffered output is printed in real-time, demonstrating how handlers can be used to manage and display process data effectively.
Tip: Debugging handler functions can be challenging because SKILL IDE doesn't highlight errors within them. Test your handlers before running long tasks. Use breakpoints, which do work, to analyze the state of your handler functions.
4.Conclusion
In this guide, we've explored how to run external tools via SKILL using system() and ipcBeginProcess(). Use system() for short tasks where output isn't needed, and ipcBeginProcess() with handlers for longer tasks requiring output handling. Each approach has its place, depending on the task at hand.
Author: Eugeny Khanchin