I'm using NSTask to run some bash commands, and have been for quite a while. Lately however, any time I try to do this, normal logging stops in the Xcode console (e.g. from NSLog or Cocoa Lumberjack). The console still shows any output that the bash commands may have, but no further logs appear.
The logs will be appearing as normal, and will stop as soon as I execute:
NSTask *someTask = [NSTask new];
NSArray *inputArgs = #[#"-l", #"-c", script];
[someTask setLaunchPath:#"/bin/bash"];
[someTask setArguments:inputArgs];
[someTask launch] // This is when the logs stop
This problem seems to have started with the upgrade to Xcode 5.1.1. Any ideas on how to bring back my lovely messages?
So this seems to be the resurgence of an old bug with Xcode. I found an old answer describing it.
In short I had to change my code to:
NSTask *someTask = [NSTask new];
NSArray *inputArgs = #[#"-l", #"-c", script];
[someTask setLaunchPath:#"/bin/bash"];
[someTask setArguments:inputArgs];
[someTask setStandardInput:[NSPipe pipe]]; // <-- Added this line.
[someTask launch]
Related
I'm not really sure how to phrase this question, but I'll try my best. I have an NSTask that currently unzips an archive, and it needs to also support archives which might have a password. I have no idea how to go about pausing the task or how to detect if a password might be present, get the input if needed then proceed, or if this is even possible?
NSTask *unzip = [[NSTask alloc] init];
[unzip setLaunchPath:#"/usr/bin/unzip"];
[unzip setArguments:[NSArray arrayWithObjects:#"-u", #"-d",
destination, zipFile, nil]];
NSPipe *aPipe = [[NSPipe alloc] init];
[unzip setStandardOutput:aPipe];
[unzip launch];
// if statement here?
[unzip waitUntilExit];
[unzip release];
From terminal stdout looks like this:
Archive: encrypted.zip
creating: test
[encrypted.zip] test password:
skipping: test incorrect password
Also I wish not to limit this to zip files, since I also use a similar task to untar/gzip archives.
Is there are way to have the NSTask pop up a modal window if it detects an archive with a password or from certain stdout it might receive?
I have created this app that make use of the /usr/bin/say command in OS X.
This method takes the value from a textfield and uses "say" to save it.
But when i run this outside xcode. I don't get the saved file.
- (IBAction)save:(id)sender
{
NSString *path;
path = #"/usr/bin/say";
NSArray *args;
args = [NSArray arrayWithObjects: #"-o", #"text.wav", #"--data-format=LEF32#8000", [textField stringValue], nil];
[[NSTask launchedTaskWithLaunchPath:path arguments:args] waitUntilExit];
NSLog(#"Saved");
}
Anyone know what i'm doing wrong?
Perhaps it's being saved but you don't know where. The path text.wav is a partial path, so it's going to be saved in the "current directory". But what directory is the "current directory"? You probably don't know.
I want a Cocoa equivalent of the command line tool open(1), especially for the usage in this form:
open -a <SomeApplication> <SomeFile> --args <Arg1> <Arg2> ...
Take QuickTime as an example. The following command line will open a file using QuickTime, and the arguments can control if QuickTime plays the file on startup.
open -a "QuickTime Player" a.mp4 --args -MGPlayMovieOnOpen 0 # or 1
I have read Launching an Mac App with Objective-C/Cocoa. prosseek's answer, which I think is equivalent to open -a <App> <File>, works well when I do not specify any argument. ughoavgfhw's answer, which I think is equivalent to open -a <App> --args <Arg1> <Arg2> ..., works well when I do not specify any file to open. But neither can specify a filename and arguments at the same time.
I have also tried to append the filename to the argument list, which is the common way used by unix programs. It seems that some applications can accept it, but some cannot. QuickTime prompts an error saying it cannot open the file. I am using the following code.
NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
NSURL *url = [NSURL fileURLWithPath:[workspace fullPathForApplication:#"QuickTime Player"]];
NSArray *arguments = [NSArray arrayWithObjects:#"-MGPlayMovieOnOpen", #"0", #"a.mp4", nil];
[workspace launchApplicationAtURL:url options:0 configuration:[NSDictionary dictionaryWithObject:arguments forKey:NSWorkspaceLaunchConfigurationArguments] error:nil];
// open -a "QuickTime Player" --args -MGPlayMovieOnOpen 0 a.mp4
It seems that the mechanism in opening files differs from usual arguments. Can anyone explain the internals of open(1), or just give me a solution? Thanks.
You might want to pipe the output of the task so you know the results. "a.mp4" needs to be the full path to the file.
NSArray *args = [NSArray arrayWithObjects:#"-a", #"QuickTime Player", #"--args", #"a.mp4", nil];
NSTask *task = [NSTask new];
[task setLaunchPath:#"/usr/bin/open"];
[task setArguments:args];
[task launch];
I'm trying to figure out how to set up IPC between my custom app and a pre-made program.
I'm using MacOSX Lion 10.7.2 and Xcode 4.2.1.
It doesn't matter actually what program exactly, since I believe that a similar reasoning may be applied to any kind of external process.
For testing purposes I'm using a simple bash script:
#test.sh
echo "Starting"
while read out
do
echo $out
done
What I would like to achieve is to redirect input and output of this script, using my app to send inputs to it and read its outputs.
I tried to use NSTask,NSPipe and NSFileHandle as follows:
-(void)awakeFromNib {
task = [[NSTask alloc] init];
readPipe = [NSPipe pipe];
writePipe = [NSPipe pipe];
[task setStandardOutput:readPipe];
[task setStandardInput:writePipe];
[task setLaunchPath:#"/path/test.sh"];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(read:)
name:NSFileHandleReadCompletionNotification
object:nil];
[[readPipe fileHandleForReading] readInBackgroundAndNotify];
[task launch];
}
-(IBAction)write:(id)sender {
NSLog(#"Write called: %d %#\n",[task isRunning],writePipe);
NSFileHandle *writeHandle = [writePipe fileHandleForWriting];
NSString *message = #"someString";
[writeHandle writeData:[message dataUsingEncoding:NSUTF8StringEncoding] ];
}
-(void)read:(NSNotification*)notification {
NSString *output = [[NSString alloc] initWithData:[[notification userInfo] valueForKey: NSFileHandleNotificationDataItem]
encoding:NSUTF8StringEncoding];
NSLog(#"%#",output);
[output release];
[[notification object] readInBackgroundAndNotify];
}
but I'm able only to read the output of test.sh, not to send it any input.
Actually any other example I saw on the web is pretty similar to my code, so I'm not sure if this issue is due to some mistake(s) of mine or to other issues (like app's sandboxing of MacOS Lion).
I've checked XPC documentation, but, according to my researches, in order to use XPC API to IPC, both sides should connect to the same service.
That's not what I'm looking for since I don't want to alter the script in any way, I just want redirect its input and output.
Is my issue due to the lack of XPC and/or to app's sandboxing?
If yes, is there a way to use XPC without modifying the script?
If no, then may somebody explain me what I'm doing wrong?
You don't need XPC for this. Won't make any difference.
Is your script / external process able to read input when you pipe something to it on the command line
% echo "foobar" | /path/test.sh
?
How much data are you sending to it. Writing will be buffered. IIRC -synchronizeFile will flush buffers -- same as fsync(2).
Is it possible to setup an Instruments run programmatically from my code? For instance, I'd like to structure my code something like this where startTrace might setup a specific probe for the current thread and start recording while stopTrace would stop recording. I would be writing the content of those routines using the Instruments API that is the subject of this question.
-(void)myInterestingMethod
{
[self startTrace];
// do something interesting and performance critical
[self stopTrace];
}
If the above isn't available, is setting up my own DTrace probe a viable alternative?
Doesn't look like there's anything straight-forward, but there is an instruments command-line tool. Here's some quick+dirty code that will invoke it and sample CPU usage for the calling process
static void sampleMe() {
// instruments -t '/Developer/Applications/Instruments.app/Contents/Resources/templates/CPU Sampler.tracetemplate' -p 26838 -l 5000
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/usr/bin/instruments"];
[task setArguments:[NSArray arrayWithObjects:
#"-t",
#"/Developer/Applications/Instruments.app/Contents/Resources/templates/CPU Sampler.tracetemplate",
#"-p",
[NSString stringWithFormat:#"%ld", getpid()],
#"-l",
#"5000",
nil]];
[task setCurrentDirectoryPath:NSHomeDirectory()];
[task setStandardInput:[NSPipe pipe]];
[task setStandardOutput:[NSPipe pipe]];
[task setStandardError:[NSPipe pipe]];
[task launch];
// purposely leak everything since I can't be bothered to figure out lifetimes
}
After invocation a file named instrumentscli0.trace will be in your home directory.
Update: Instruments 4.0 offers DTSendSignalFlag in the DTPerformanceSession for iOS apps.