Ok, so I know you can make an NSTask to run command line tools with Objective-C:
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: #"/usr/bin/gdb"];
[task launch];
I'm just wondering if there's a way to communicate with interactive command line tools such a as gdb. This would involve giving the command inputs based on user interaction (like run, kill or quit with gdb) and then reacting based on the information it outputs.
You can use NSTask's setStandardInput:, setStandardOutput: and setStandardError: selectors in conjunction with NSPipe instances to communicate with the launched program.
For example, to read the task's output:
task = [[NSTask alloc] init];
[task setStandardOutput: [NSPipe pipe]];
[task setStandardError: [task standardOutput]]; // Get standard error output too
[task setLaunchPath: #"/usr/bin/gdb"];
[task launch];
You can then obtain an NSFileHandle instance that you can use to read the task's output with:
NSFileHandle *readFromMe = [[task standardOutput] fileHandleForReading];
To set up a pipe for sending commands to gdb, you would add
[task setStandardInput: [NSPipe pipe]];
before you launch the task. Then you get the NSFileHandle with
NSFileHandle *writeToMe = [[task standardInput] fileHandleForWriting];
Use setStandardInput: and setStandardOutput: methods of NSTaks class.
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: #"/usr/bin/gdb"];
NSPipe *outputpipe=[[NSPipe alloc]init];
NSPipe *errorpipe=[[NSPipe alloc]init];
NSFileHandle *output,*error;
[task setArguments: arguments];
[task setStandardOutput:outputpipe];
[task setStandardError:errorpipe];
NSLog(#"%#",arguments);
output=[outputpipe fileHandleForReading];
error=[errorpipe fileHandleForReading];
[task launch];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedData:) name: NSFileHandleReadCompletionNotification object:output];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedError:) name: NSFileHandleReadCompletionNotification object:error];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(TaskCompletion:) name: NSTaskDidTerminateNotification object:task];
//[input writeData:[NSMutableData initWithString:#"test"]];
[output readInBackgroundAndNotify];
[error readInBackgroundAndNotify];
[task waitUntilExit];
[outputpipe release];
[errorpipe release];
[task release];
-(void) receivedData:(NSNotification*) rec_not {
NSFileHandle *out=[[task standardOutput] fileHandleForReading];
NSData *dataOutput=[[rec_not userInfo] objectForKey:NSFileHandleNotificationDataItem];
if( !dataOutput)
NSLog(#">>>>>>>>>>>>>>Empty Data");
NSString *strfromdata=[[NSString alloc] initWithData:dataOutput encoding:NSUTF8StringEncoding];
[out readInBackgroundAndNotify];
[strfromdata release];
}
/* Called when there is some data in the error pipe */
-(void) receivedError:(NSNotification*) rec_not {
NSFileHandle *err=[[task standardError] fileHandleForReading];
NSData *dataOutput=[[rec_not userInfo] objectForKey:NSFileHandleNotificationDataItem];
if( !dataOutput)
NSLog(#">>>>>>>>>>>>>>Empty Data");
else {
NSString *strfromdata=[[NSString alloc] initWithData:dataOutput encoding:NSUTF8StringEncoding];
[strfromdata release];
}
[err readInBackgroundAndNotify];
}
/* Called when the task is complete */
-(void) TaskCompletion :(NSNotification*) rec_not {
NSLog(#"task ended");
}
Related
I have an OS X App, it makes a call to shell script using this:
#implementation ViewController {
NSTask *task;
NSPipe *pipe;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self runCommand:[[NSBundle mainBundle] pathForResource:#"Test" ofType:#"command"] arguments:nil];
}
- (void)runCommand:(NSString *)cmd arguments:(NSArray *)args {
if (task)
{
[task interrupt];
}
else
{
task = [[NSTask alloc] init];
[task setLaunchPath:cmd];
[task setArguments:args];
pipe = [[NSPipe alloc] init];
[task setStandardOutput:pipe];
NSFileHandle* fh = [pipe fileHandleForReading];
[task launch];
[fh readInBackgroundAndNotify];
}
}
#end
The shell script Test.command has output text which will be displayed in Terminal window when you execute it in Terminal, but is there a way to retrieve this output in my OS X App and display it into a text view?
You need to observe the notification event fired by the task. The order in which you register the observer and launch the command is also important. Try something like:
{
task = [[NSTask alloc] init];
[task setLaunchPath:cmd];
[task setArguments:args];
pipe = [[NSPipe alloc] init];
[task setStandardOutput:pipe];
// Observe events before launching the task, otherwise the execution
// might end before we get the chance to register the observer.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didCompleteReadingFileHandle:)
name:NSFileHandleReadCompletionNotification
object:[[task standardOutput] fileHandleForReading]];
// Make it start reading before launching.
[[pipe fileHandleForReading] readInBackgroundAndNotify];
// Launch it.
[task launch];
}
- (void)didCompleteReadingFileHandle:(NSNotification *)notification
{
NSData *data = [[notification userInfo]
objectForKey:NSFileHandleNotificationDataItem];
// Do something with data...
}
In my NSApplication I've a button. When I click it, I want to launch/start a daemon/agent. How can I proceed? I've already tried:
- (void) runAgent {
NSTask *task = [[NSTask alloc] init];
task.launchPath = #"launchctl load /System/Library/LaunchAgents/com.mycompany.myagent.plist";
[task setLaunchPath:#"/bin/sh"];
[task launch];
}
with no success...
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/bin/launchctl"];
[task setArguments:[NSArray arrayWithObjects:#"load",#"/System/Library/LaunchAgents/com.mycompany.myagent.plist", nil]];
[task launch];
I am very new to develop mac osx application using xcode. I am trying to get all running application list with their memory usage.
Can any body help me in this case.
Please help me.
Thanks in advance.
It will help you to get list of running application :
for (NSRunningApplication *app in [[NSWorkspace sharedWorkspace] runningApplications]) {
NSLog(#"%#",[app localizedName]);
}
You may get the cpu usage as:
- (NSString*) get_process_usage:(int) pid
{
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath:#"/bin/ps"];
NSArray *arguments;
arguments = [NSArray arrayWithObjects: #"-O",#"%cpu",#"-p",[NSString stringWithFormat:#"%d",pid], nil];
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *string;
string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSString* temp = [string stringByReplacingOccurrencesOfString:#"PID %CPU TT STAT TIME COMMAND" withString:#""];
NSMutableArray* arr =(NSMutableArray*) [temp componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[arr removeObject:#""];
[string release];
[task release];
if([arr count]>=2)
return [arr objectAtIndex:1];
else
return #"unknown";
}
Thanks for the help. The results of this executed command is displayed in my Xcode Console. What's the best way to get the results of the command to be displayed in an NSTextView?
NSString *commandToRun = #"~/Library/webREF/ffmpeg -nostats -i ~/Desktop/input.wav - filter_complex ebur128 -f null -";
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: #"/bin/sh"];
NSArray *arguments = [NSArray arrayWithObjects:
#"-c" ,
[NSString stringWithFormat:#"%#", commandToRun],
nil];
NSLog(#"run command: %#",commandToRun);
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
Add something like:
…
NSFileHandle *file;
file = [pipe fileHandleForReading];
NSMutableData *data = [[NSMutableData alloc] init];
NSData *inData = nil;
[task setStandardOutput:pipe];
[task launch];
[task waitUntilExit];
while ((inData = [file availableData]) && [inData length]) {
[data appendData:inData];
}
[file closeFile];
[task release];
[pipe release];
NSString *result = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
[data release];
// somewhere we have an NSTextView textView
[textView setString: result];
I was wondering how I would output text from NSTask and send it to a NSTextField on OSX.
I googled NSTask and got this...
but here is the code to do what you want.
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: #"/bin/ls"];
NSArray *arguments;
arguments = [NSArray arrayWithObjects: #"-l", #"-a", #"-t", nil];
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *string;
string = [[NSString alloc] initWithData: data
encoding: NSUTF8StringEncoding];
[myTextField setStringValue: string];