Shell: is this worth a feature request?

and is it even possible Xplatform?

I have been needing to shell out to some open source command line software… for many uses is meant to take a file in and produce a different file out and also writes a success or and fail messages to Stdout.

Both for performance and wear and tear on the disk, if the saving is not needed ,it would be best to avoid writing files to disks one has to do it thousands of times…

For most of my needs I have been able to use echo in place of the input file, but if I route the output to StdOut sometimes it is too big , and other times, depending on timing, the success message can be mixed into the file content causing issues… So I have had to actually output result the files to disk.

It would be nice if there was a way built into the framework to hook in a string or a memoryblock in place of the input and/or output files for use in shell commands … I guess sort like a RAMDisk as far as the OS is concerned.

I don’t know if this is something that would be generally useful enough for Xojo inc to even bothering to consider implementing… what do others think?

  • Karen

It’s something that I’ve thought about for sure.

If you’re writing your own helper console applications, then you can use shared memory, a chunk of memory that both the GUI and helper can access.

Two problems with this exist (that I can see right now).

  1. If you didn’t create the helper, then I think most likely your SOL.
  2. I spent some time figuring out how to do shared memory on the macOS, only to have Apple block it as part of their “security” protocols. There might be some safe shared memory functions, but it’s not clear from the documentation which is and which isn’t.

For macOS, while not using shared memory per se, using NSTask in lieu of Shell and capturing StdOut and StdErr via pipes can monitor another helper app in real time without using a disk file. MBS even has an example demo program here . It just uses StdOut but the same principle applies to StdIn and StdErr as well.

can you switch to using an interactive shell and then just concatenate the output from it in the dataAvailable event? That seems like what you really want to do.

It might add complexity as an interactive shell is not synchronous so your code will not stop after you start the shell. So you’ll have to start the next bit of code from the completion event of the shell but otherwise it should be a lot simpler than adapting the shell commands to output to shared memory.

In MBS Xojo Plugins, we have WindowsProcessMBS class in our MBS Xojo Win Plugin for Windows and for Mac the NSTaskMBS class in MBS Xojo MacCocoa Plugin for MacOS.
You could write a wrapper to give both an unified interface.

I do it with a locally instanced async shell. Of course, it involves the dreaded App.DoEvents, but it would go something like this:

[code]Dim theShell As New Shell
Dim theOutput As String
Dim theCmd As String

theCmd = “echo " + g_inputString + " | " + theCLIToolAndArgs + " -f -”
theShell.Mode = 2
theShell.Timeout = -1
theShell.Execute thCmd
Do
App.DoEvents(5)
theShell.Poll
theOutput = theOutput + theShell.ReadAll
Loop Until Not theShell.IsRunning[/code]
This works for processes that run for days and generate 10’s of GB of output. Of course, I am writing to a file instead of building a single string, but the only limitation to this for you is memory and how large each of the resulting files is.

[quote=419292:@Tim Jones]I do it with a locally instanced async shell. Of course, it involves the dreaded App.DoEvents, but it would go something like this:

[code]Dim theShell As New Shell
Dim theOutput As String
Dim theCmd As String

theCmd = “echo " + g_inputString + " | " + theCLIToolAndArgs + " -f -”
theShell.Mode = 2
theShell.Timeout = -1
theShell.Execute thCmd
Do
App.DoEvents(5)
theShell.Poll
theOutput = theOutput + theShell.ReadAll
Loop Until Not theShell.IsRunning[/code]
This works for processes that run for days and generate 10’s of GB of output. Of course, I am writing to a file instead of building a single string, but the only limitation to this for you is memory and how large each of the resulting files is.[/quote]

I see how that would work …

First let me say I don’t know command line stuff for any OS well.

In your code I assume “f -” is redirecting what should be the output file content to stdout…

If that is right how does one differentiate the output meant to go to the ‘file’ and success/failure message the tool writes to StdOut?

When the output files were small enough for Stdout, I would get those messages mixed in with the ‘file’ output.

That is why i mentioned a RamDisk like functionality… That was so the OS sees it as writing to something different than Stdout, so the two output don’t get mixed together.

  • Karen

Speaking of shared memory between different applications, has anyone implemented something like that on Windows?
(I’d be very curious about it)

You are correct, but a proper Unix-y CLI app will redirect non-data to stderr (2) when it sees that data is being written to stdout (1).

To check this in your app, execute the app on the command line with a bad command and redirect 2 to /dev/null. Something like this:

cp -Ree /usr/bin/mdfind /tmp

You will see the error message. Send stderr to /dev/null:

cp -Ree /usr/bin/mdfind /tmp 2>/dev/null

You don’t.

Your tool should have similar operation and you should check for theShell.ErrorCode.