Shell command not outputting to textArea

Hi All.

I have got to be doing something wrong, so hopefully someone can point out my error.

Using a shell, I am running a command to change my directory to Documents (in Mac Catalina), and then just print out the directory.

When I run this code, all I get in my textArea is a single ‘/’

Var s, s1 As Shell
s = New Shell
s1 = new shell

#If TargetWindows Then
s.Execute(“dir”)
#ElseIf TargetMacOS Or TargetLinux Then
s1.Execute(“cd /Users/<myUserName/Documents”)
s1.Execute(“pwd”)
#Endif
If s.ErrorCode = 0 Then
TextArea1.Value = s1.Result
Else
MessageBox("Error code: " + s.ErrorCode.ToString)
End If

I have confirmed that the commands are correct, running them in terminal.

Can someone see what I am doing wrong?

A shell isn’t the same environment as a system shell (terminal). From the docs:

The Shell is not equivalent to the Terminal or Command app for your OS. Paths and other default settings will likely not be the same. If you need to do configuration of the Shell before you use it, be sure to set it up to be interactive so you can set up the configuration before calling other shell commands. Alternatively you could create a batch file that sets everything up and call that instead.

This is the result I get, as well.

BTW, you only need one shell declaration; note that you’ve enclosed your output from s1 with a test of the ErrorCode from s (which just happens to be 0 by default)

Try it this way:

Var s As New Shell
s.Timeout = -1
s.Mode = 1

#If TargetWindows Then
    s.Execute(“dir”)
#ElseIf TargetMacOS Or TargetLinux Then
    s.Execute(“cd """ + SpecialFolder.Documents.NativePath + """ ; pwd”)
#Endif
Do
    s.Poll
    App.DoEvents
Loop Until Not s.IsRunning
If s.ErrorCode = 0 Then
    TextArea1.Value = s.ReadAll
Else
    MessageBox("Error code: " + s.ErrorCode.ToString)
End If

Do NOT deploy this as production code, as it contains the dreaded DoEvents. In fact, this polling code is unnecessary since the Shell is already in Synchronous (Mode=1) mode.

Michael, your code is already correct insofar as you are getting something valid in Shell.Result. As noted by another reply, your issue lies elsewhere, likely in the shell’s environment.

The dreaded DoEvents is for console, never use it in GUI

1 Like

And don’t be so sure about the use of App.DoEvents(). In this case, it is perfectly acceptable and does not cause any unexpected results.

Do yourself a favor and try my method.

1 Like

But seriously - if this is not a console app, you will save yourself a lot of trouble down there line by simply forgetting that DoEvents even exists. The funny thing about DoEvents is that it causes no ill side effects until it does, randomly, and then you have no idea that it is the culprit.

In the case of Tim’s suggestion that you try a Mode=1 shell, a better approach is to use the shell’s Completed event to detect when the command has terminated rather than consuming resources polling it. Then you can use the Shell.Result property to retrieve the output of the command. Structuring your app to respond to events instead of polling is how Xojo is designed to operate and really will save you a lot of restructuring later.

DoEvents was made for console

You may want to try:

Loop Until Not s.IsRunning
If s.ErrorCode = 0 Then
    TextArea1.Value = TextArea1.Value + s.ReadAll
Else
    MessageBox("Error code: " + s.ErrorCode.ToString)
End If

In this case, the concatenation isn’t needed since the commands are “one shot” and the information is not displayed until the task is compete. If it was a task that runs for a long time - a large folder copy operation, for instance, that would be important to keep the information appearing during the task instead of all at once at the end:

Var s As New Shell
s.Timeout = -1 // why isn't this the default? <[https://xojo.com/issue/32971](https://xojo.com/issue/32971)>
s.Mode = 1

#If TargetWindows Then
    s.Execute(“xcopy /s E:\DCIM\* D:\Photos\”)
#ElseIf TargetMacOS Or TargetLinux Then
    s.Execute(“cp -r -v """ + sdcard().Child("DCIM").NativePath + """ ""/Volumes/PhotoStore/My Photos"""")
#Endif
Do
    s.Poll
    TextArea1.Append = s.ReadAll
    App.DoEvents
Loop Until Not s.IsRunning
If s.ErrorCode = 0 Then
    MessageBox("Camersa card copy operation completed.")
Else
    MessageBox("Error code: " + s.ErrorCode.ToString)
End If

Thanks guys. I’m giving this a try and will advise. I think the immediate might do what I want.

Regards