4

I have something like:

- (NSString *)unixSinglePathCommandWithReturn:(NSString *)command
{
NSPipe *newPipe = [NSPipe pipe];
NSFileHandle *readHandle = [newPipe fileHandleForReading];

NSTask *unixTask = [[NSTask alloc] init];
[unixTask setStandardOutput:newPipe];
[unixTask setLaunchPath:@"/bin/sh"];
[unixTask setArguments:[NSArray arrayWithObjects:@"-c", command , nil]]; 
[unixTask launch];
[unixTask waitUntilExit];

NSString *output = [[NSString alloc] initWithData:[readHandle readDataToEndOfFile] encoding:NSUTF8StringEncoding];

return output;
}

But it doesn't work as expected. I call it when i click a button. If i remove the line with 'waitUntilExit' it works as expected, but only once. When it's there, it doesn't work. I tried also some basic commands like 'ls' 'ping -c1 google.com' and stuff like that, but i can't get it to work somehow. If you have some different approach to run shell scripts in cocoa with receiving the response, please let me now. Thank you all :)

2
  • Hi, interesting - this code works well for me. However for some reason it messes with NSLog - and NSLog won't display anything for me, but when run directly from the console it will work as expected. I haven't changed your code in any way .... Commented Jan 10, 2011 at 22:47
  • possible duplicate of Execute a terminal command from a Cocoa app Commented Sep 14, 2014 at 21:31

4 Answers 4

5

Hey, Kukosk. There’s a comment on CocoaDev about NSLog() issues when running an NSTask. The fix is to set a pipe for stdin before launching the task:

[task setStandardInput:[NSPipe pipe]];

If you’re relying on NSLog() only to check whether the task has run, this might fix your problem. Alternatively, you could try to present output in your GUI instead of using NSLog().

Sign up to request clarification or add additional context in comments.

1 Comment

thanks @bavarious you saved my day! Wait, aren't you the same person in another NSTask thread??? :) God bless you...
2

The problem is that you aren't emptying the output buffers of the task. You can't simply launch a task and waitUntilDone unless the task also emits an extremely small amount of data.

waitUntilDone will obviously not work at all with a task that never exits.

For a task that emits any quantity of output, you need to set it up such that the output is read as it is generated. Typically, you use readInBackgroundAndNotify or a variant therein.

In any case, the top of the class description for NSTask has both links to the conceptual guide and to a series of examples that cover this.

2 Comments

So what do i have to do in general? Can u please post the working code with a bit explanation, please? It will really help! I am familiar with obj.c, but i was coding for the iOS platform, so some things i have never used are kinda new for me :) thank you for your response.
The NSTask documentation goes in depth on the subject, including extensive examples.
0

Ah, there's a very important line in the docs you seem to have missed, one of those irritations that NextStep seems to like: "An NSTask object can only be run once. Subsequent attempts to run the task raise an error."

So, bag the wait, and add [unixTask release] before the return. When you want to run it again, remake the task.

NSTimer is like this.

3 Comments

OP is making a new task on each invocation to that method. That isn't the problem (though you are correct in that said code is leaking the task).
He’d also be leaking the output string, except that I know for a fact he’s using garbage collection. Hey, Kukosk. =P
im using the gc ;) but i will release it since it'll work even if i use gc
0

For different approaches to run shell scripts in Cocoa have a look at AMShellWrapper, PseudoTTY.app or OpenFileKiller!

http://www.cocoadev.com/index.pl?NSTask

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.