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.
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)
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.
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.
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