Con frecuencia es necesario ejecutar algún comando externo, como por ejemplo un programa Python o un script de bash desde Caché/Ensemble. Existen dos formas principales:
USER>set tCurrentDevice=$IO USER>set tDevice="|CPIPE|" USER>set tCmd="bash" USER>set tInstructions="vi /Users/afuentes/test.txt"_$c(13,10)_"i"_"Hellow World!"_$c(27)_":wq"_$c(13,10)_"exit"_$c(13,10) USER>open tDevice:(tCmd:"W") USER>use tDevice Write tInstructions Use tCurrentDevice USER>close tDeviceSi lo único que precisamos es ejecutar un comando y obtener la salida, podemos hacer como en el siguiente ejemplo en el que se muestra la salida de un listado de directorios.
USER>set tDevice="|CPIPE|" USER>set tCmd="ls -l" USER>open tDevice:(tCmd:"R") USER>use tDevice Read line Use 0 Write line total 1028 USER>use tDevice Read line Use 0 Write line -rw-rw---- 1 root irisusr 1048576 Jul 1 14:58 IRIS.DAT USER>use tDevice Read line Use 0 Write line -rw-rw---- 1 root irisusr 40 Jul 1 14:07 iris.lck USER>use tDevice Read line Use 0 Write line drwxrwxr-x 2 root irisusr 64 Apr 30 19:12 stream USER>use tDevice Read line Use 0 Write line USE tDevice READ line USE 0 WRITE line ^ <ENDOFFILE> USER>Como veis, podemos continuar leyendo del dispositivo CPIPE hasta alcanzar el <ENDOFFILE>. Así que probablemente en el código habría que añadir un bloque try-catch. Fijaos como además se utiliza directamente Use 0 porque estamos ejecutándolo desde un Terminal, pero en general, al igual que en el ejemplo anterior, podemos hacer uso de $IO para obtener el dispositivo abierto actual. Elegiremos el método de ejecución que más nos convenga según las necesidades. En cualquier caso, merece la pena echarle un vistazo a la clase %Net.Remote.Utility y los métodos RunCommandViaZF y RunCommandViaCPIPE que encapsulan el funcionamiento de estas funciones de ejecución de comandos externos.
USER>set cmd="/bin/bash" USER>set arg=2 USER>set arg(1)="-c" USER>set arg(2)="ps -fea | grep iris" USER>set ret = ##class(%Net.Remote.Utility).RunCommandViaCPIPE(cmd, .device, .out,,,.arg) USER>close device USER>set outList = $listfromstring(out, $c(13,10)) USER>write $listget(outList, 1) root 1 0 0 04:25 ? 00:00:00 /dev/init -- /iris-main --key /external/iris.key USER>write $listget(outList, 2) root 7 1 0 04:25 ? 00:00:01 /iris-main --key /external/iris.key USER>write $listget(outList, 3) root 772 1 0 04:25 ? 00:00:01 /usr/irissys/bin/irisdb -s/external/durable/mgr/ -w/external/durable/mgr/ -cc -B -C/external/durable/iris.cpf*IRIS USER>write $listget(outList, 4) root 773 772 0 04:25 ? 00:00:00 /usr/irissys/bin/irisdb WDTened en cuenta que si la salida de nuestro comando es mayor que el tamaño máximo de un string (3 641 144 caracteres), podemos redirigir la salida a un fichero temporal.
USER>set cmd="/bin/bash" USER>set arg=2 USER>set arg(1)="-c" USER>set arg(2)="ls -l > /tmp/ls.txt" USER>set ret=##class(%Net.Remote.Utility).RunCommandViaCPIPE(cmd, .device, .out,,,.arg) USER>write ret 1 USER>close device USER>set file=##class(%Stream.FileCharacter).%New() USER>set file.Filename="/tmp/ls.txt" USER>write file.ReadLine() total 1028 USER>write file.ReadLine() -rw-rw---- 1 root irisusr 1048576 Jul 1 14:58 IRIS.DAT USER>write file.ReadLine() -rw-rw---- 1 root irisusr 40 Jul 1 14:07 iris.lck