Swift and NSTask hangs - xcode

i am new to the Mac World. I'm using Swift and i am trying to run external processes one at a time.
Now everything works fine, as long, as it is debugged, by which I mean: Run in Xcode with Debugger attached.
I do not change anything and try to run it in the terminal window, from it's place in the "Debug" folder. Now the external process starts but hangs.There is some STDERR output, which I already switched off. And there is DiskIO by the external Task.
let video : NSTask = NSTask()
video.launchPath = "./ffmpeg"
video.arguments = ["-i", "\(item)", "-c:v","copy", "-bsf:v", "h264_mp4toannexb", "-an", "-y", "-loglevel", "quiet", "\(path).h264"]
//also tried without the following two lines
video.standardError = NSFileHandle.fileHandleWithStandardError()
video.standardOutput = NSFileHandle.fileHandleWithStandardOutput()
video.launch()
video.waitUntilExit()
Yes: I copied everything to the current path, so that execution works. It starts but hangs when run from terminal.
Now the Question arises: WHY?! What am I doing wrong here? The easy solution would be to always run it in Xcode, but as you might imagine, that is quite inconvenient with a command line tool.

You need to redirect stdin from /dev/null. ffmpeg has an open stdin and is waiting for more data on that pipe.
video.standardInput = NSFileHandle.fileHandleWithNullDevice()
Note that you don't need your assignments to standardError and standardOutput. Those are the default settings.
This works in Xcode because the debugger closes stdin for you.

Related

Is there a way to send a running terminal command to the background AND change the output to pipe to a log file?

Sometimes when I run a log running terminal command, I'd like to send it to the background and start doing something else in the same shell. I can do this with Ctrl+Z and bg.
However, the annoying effect this has is that it keeps showing output of the above command intermittently. Instead, when I move the process to the background, I'd also like to change where the output goes as well.
Importantly, I'm asking how to do this for an already-running command - I know that do this from scratch I could do something like command arg1 arg2 &> ~/logs/output.log &.
I have used Reptyr for this in the past.
It does have its limitations (especially with GUIs / Curses) but has worked well for me.
https://linux.die.net/man/1/reptyr
You can either start a Screen session and use reptyr to grab your running process into the screen session. Or start a new bash session which is outputting to a file and then grab the running process with reptyr.

How can I execute Windows commands from Perl without leaving command windows open?

I have a Perl script on Win10 that uses the system() command to run a couple of different command line processes, including:
Start Windows Media Player with a specified .mp3 file.
my $cmd = "start call wmplayer.exe myRadoShow.mp3";
system($cmd);
Start another Perl program that does something else at the same time (specifically reads and broadcasts a set of timecodes and titles).
my $cmd2 = "secondScript.pl some_params";
system($cmd2);
All of this works correctly; the minor problem is that #1 above starts up a new command line window each time it executes the system($cmd) command. I have to later go back and close those windows.
If I don't use "start call" the Perl script doesn't continue to #2.
Is there a preferred way to execute #1 that doesn't leave these windows open?
I realize this question may be more about Windows commands than Perl.
Firstly, If youre using active perl versions, there is a wperl.exe you can call your script with instead of the default perl.exe. Not to sure if this will hide sub processes created by your script but you can give it a go.
If that doesnt work, then maybe you can use Win32::GUI:
use Win32::GUI;
my $hw = Win32::GUI::GetPerlWindow();
Win32::GUI::Hide($hw);
there are other modules that provide this functionality as well. Good luck!

Redirecting cmd stdout and stderr back to parent

If I create a process from a cmd prompt using the start command (opening a new cmd) is it possible to redirect the stdout and stderr from that process back to the calling cmd?
If you want the output of the STARTed process to appear in the parent command console, then simply use the START /B option.
If you want to process the output of your command, then you should use FOR /F ... in ('someCommand') DO ... instead.
OK. I have yet to find a straightforward answer to this question. I didn't want to bog down my question with what I thought unnecessary detail but seeing as I'm being criticized for the lack of this I'll expand a bit here.
I want to automate the updating of FWs on our production line, so I've a python app that gets the FWs from ftp and then uses the processors flash tool via python subprocess command to upload it to the board's flash. OK for all but one of the tools.
The one tool seems to have a problem when it's not running in its own terminal, so I provide a start to the subprocess command string which allows it to run OK in its own terminal. However, I need the output from this other terminal for logging reasons.
A possible solution was to log stdout and stderr to file using >> or wintee and then poll this file via a thread in my original app (perhaps a rather convoluted solution to the question). However the tool also has a separate problem where it doesn't like any std redirection, so this doesn't work for me.

Starting a Background Instance of Matlab on Mac OS X

In Windows you can use the following command in Matlab to start a new instance of MATLAB which will run in the background (i.e. you can keep executing commands in your first version of MATLAB).
system('matlab &')
An analogous call in OSX,
system([matlabroot '/bin/matlab &'])
however results in the display of the splash image, then nothing. If I take out the ampersand, the new instance opens as expected. Unfortunately, this won't work for me, I really need to be able to control the first instance of MATLAB while the second is running.
Does anyone know why this discrepancy between the operating systems exists? By the way, I'm using OSX 10.7, Windows 7 64 bit, and MATLAB R2012a on Mac and R2012b on PC.
As some background, I'm trying to write a generic tester for an interactive command line interface that uses the input() function extensively.
Edit: I should have mentioned that the command
/Applications/MATLAB_R2012a.app/bin/matlab &
works as expected from the OSX terminal. In other words, a new instance of MATLAB opens and new commands can be entered into the terminal. So this problem seems to be specific to the system() function in OSX matlab.
Also, I tried adding that command to a bash script and calling the script from matlab, but had the same problem that I did with putting the command into the system() function.
Thanks
This is a long shot, but it might be happening because when you invoke the new instance of Matlab from Matlab with the system() command on Unix or OS X, the matlab_helper process forks and runs a shell process to run the new application. If you omit the ampersand, the shell blocks and waits for the program to finish, and system() waits for it, so the first Matlab locks up. And (here's the speculation part) if you add the ampersand, Matlab launches in the background, and then the forked shell exits, which then causes the new Matlab process to exit because its parent process (the shell) has exited. (Windows doesn't have the same parent/child process relationships, process launch mechanism, or shells, which would explain the different behavior.)
You could try prefixing the command with nohup, which protects processes from getting killed by SIGHUP, which might be what's happening here to your second Matlab process.
system(['nohup ' matlabroot '/bin/matlab &'])
You could also try using the OS X open command to launch a new independent instance. Something like this. You may need to fiddle with the options and path, but -n should be what gives you a new instance. It should be pointing at /Applications/MATLAB_R2012a.app; I'm assuming that's what matlabroot is returning on OS X.
system(['open -na ' matlabroot])
You could also try running it from the Java process-launching features from within Matlab instead of with system(). Runtime.exec() doesn't block like system() does, and there may be other quirks to system(), like the matlab_helper architecture. Try launching it with java.lang.Runtime from Matlab.
jrt = java.lang.Runtime.getRuntime();
newMatlabProcess = jrt.exec([matlabroot '/bin/matlab']);
You can try the other command line variants above using this mechanism too, and you may need to redirect stdout to /dev/null, since the new processes input and output are buffered in to that newMatlabProcess object.
You can use applescript to do this. I do something like this:
! osascript -e "tell application \"Terminal\" to do script \"cd `pwd`;matlab -nojvm -nosplash -r 'why'\""
This example opens a new Matlab instance, in the current directory, and runs the command "why". You can remove the "-nojvm" if you need java in your background Matlab process

Is there any way to redirect stderr output from a command run with “start” in the Windows command line?

I have a program that I want to automate runs for, since it takes awhile to complete. For some reason it outputs everything to stderr instead of stdout, and I'd like to check on its progress, so I find myself needing to redirect stderr output within a start command.
I tried this:
start "My_Program" "C:\Users\Me\my_program.exe" --some --presets --for --my_program.exe --output "C:\Users\Me\output_file_for_my_program" "C:\Users\Me\input_file_for_my_program" 2>"C:\Users\Me\my_program_output.log"
But it turns out that the redirect is being picked up by start, so that I get a 0-byte file with the result of "start" - namely, nothing. Is there any way to make the output redirection attach in some way to the output of my_program?
I've experimented with escaping, and neither "^2>" nor "2^>" seem to work.
If "Workaround Oriented Programmming" is acceptable (it probably is, you are programming Windows Batch lol), you could put the problematic code line in another .BAT file, without any "start" and then "start" this other BAT.

Resources