The simplest way to read data from a process is to use the short form of the SHELL or EXEC instruction - called quick syntax:
SHELL sCommand TO (String-)Variable # sCommand ist ein String EXEC aCommand TO (String-)Variable # aCommand ist ein (String-)Array
If you use the quick syntax, the specified command Command is executed and the interpreter waits for it to finish! Afterwards, the complete output of the data is written into the specified (string) variable - as long as no process error (!) occurred.
Example 1:
Public Sub btnExecuteInstruktion_Click() EXEC ["pstree", "-p"] TO TextArea.Text End
The complete output of the process tree is displayed in a TextArea. It could hardly be quicker and more elegant.
If the process could not be started - instead of pstree, for example, there is only pstre - then you receive the error message “Cannot run child process: cannot exec program …” in the IDE. You can catch such a (start) error in the programme like this:
Public Sub btnExecuteInstruktion_Click() TextArea1.Clear Try Exec ["pstree", "-p"] TO TextArea1.Text If Error Then Message.Error("Error while executing the command!") Return Endif End
Example 2:
It is only to be checked from a Gambas programme whether the compilation of a certain Gambas project was successful or whether an error occurred during compilation:
Public Sub btnExecuteInstruktion_Click() Dim sOutput As String Shell "gbc3 $HOME/color_select 2>/dev/null || echo $?" TO sOutput If Upper(Left(sOutput, 2)) <> "OK" Then Message.Error("An error occurred during compilation!") Else Message.Info("The compilation was successful!") Endif End
As outputs you can expect the 'OK' from the standard output if the compilation was successful or a return value ≥ 1 in case of an error of the program 'gbc3' via the bash variable $? The standard error output was redirected into electronic nirvana in this example. If you only want to catch and display an error, dispense with the else branch.
Example 3 - Project
Example 3 presents a complete project for Quick-Syntax. The external programme is 'ping', with which you measure the signal runtimes for a certain server. Under 'man ping' or 'info ping' or 'ping -help' you will find interesting details about the console programme ping. The URL is freely selectable. The number of pings has been fixed at 4 and cannot be changed. In the Gambas programme, the quick syntax for SHELL and EXEC has been used. An LED signals the programme status or that of the started process, in which you cannot intervene!
Figure 21.3.1.1: GUI for the 'ping' programme
Source code:
' Gambas class file Private sProgrammName As String = "ping" Public Sub Form_Open() FMain.Center FMain.Resizable = False SetLEDColor("orange") End Public Sub btnPingOverShell_Click() Dim sAusgabe, sCommand As String SetLEDColor("green") TextArea.Clear Wait FMain.Mouse = Mouse.Wait sCommand = sProgrammName & Chr(32) & TextBox1.Text & " -c 4" Shell sCommand To TextArea.Text FMain.Mouse = Mouse.Default SetLEDColor("orange") End Public Sub btnPingOverExec_Click() Dim sAusgabe As String Dim aCommand As New String[] SetLEDColor("green") TextArea.Clear Wait FMain.Mouse = Mouse.Wait aCommand = [sProgrammName, TextBox1.Text, "-c", "4"] '-- Inline-Array Exec aCommand To sAusgabe TextArea.Insert(gb.NewLine & sAusgabe) FMain.Mouse = Mouse.Default SetLEDColor("orange") End Public Sub SetLEDColor(sLEDColor As String) PictureBox1.Picture = Picture["LED/led_" & sLEDColor & ".svg"] End Public Sub btnClose_Click() FMain.Close() End
Comments:
In the following example, on the other hand, the output is extensively processed to provide the content for a ComboBox in the main programme:
PUBLIC SUB RS232ListeGenerieren() DIM iCount AS Integer DIM sZeile, sListeV24, sListeUSB, s AS String DIM aSchnittstellenMatrix AS NEW String[] DIM aListe AS NEW String[] cmbRS232PortName.Clear() '-- Delete ComboBox content '-- Ermittlung echter RS232-Schnittstellen SHELL "dmesg | grep ttyS | grep 00:" TO sListeV24 IF Len(sListeV24) > 0 THEN aSchnittstellenMatrix = Split(sListeV24, " ") FOR EACH sZeile IN aSchnittstellenMatrix IF InStr(sZeile, "ttyS") THEN cmbRS232PortName.Add("/dev/" & Trim$(sZeile)) ENDIF NEXT ENDIF '-- Determining the USB-RS232 adapter interfaces SHELL "dmesg | grep ttyUSB" TO sListeUSB IF Len(sListeUSB) > 0 THEN aSchnittstellenMatrix = Split(sListeUSB, "\n") FOR EACH sZeile IN aSchnittstellenMatrix FOR iCount = 0 TO 7 IF InStr(sZeile, "ttyUSB" & CInt(iCount)) THEN aListe.Add("ttyUSB" & CInt(iCount)) ENDIF NEXT NEXT ENDIF aListe.Sort aListe = RemoveMultiple(aListe) FOR iCount = 0 TO aListe.Max PRINT aListe[iCount] cmbRS232PortName.Add("/dev/" & Trim$(aListe[iCount])) NEXT ' iCount IF cmbRS232PortName.Count = 0 cmbRS232PortName.Background = Color.RGB(255, 191, 191) cmbRS232PortName.Add("No RS232 interface found!") ENDIF END PUBLIC FUNCTION RemoveMultiple(aStringListe AS String[]) AS String[] DIM iCount AS Integer DIM iIndex AS Integer DIM sElement AS String iIndex = 0 WHILE iIndex < aStringListe.Count iCount = 0 sElement = aStringListe[iIndex] WHILE aStringListe.Find(sElement) <> -1 INC iCount aStringListe.Remove(aStringListe.Find(sElement)) WEND IF iCount MOD 2 = 1 THEN aStringListe.Add(sElement, iIndex) INC iIndex ENDIF WEND RETURN aStringListe END