Pass data into a tool's stdin using NSTask - objective-c

Let's say I have some tool that, at some point in its execution, asks for user input. For example, it might ask for name and address. At another point it might ask for a password (and retyping of the password).
Is it possible for NSTask and NSPipe objects to deal with these things, i.e. to interact with command line tools?

See the setStandardInput: method of NSTask. It allows you to set either a NSPipe or NSFileHandle as the task's standard input before launching it. There are also similar methods for standard output and standard error.

Related

NSTask vs System - pros and cons?

I'm at a point in a project where I need to call system commands. I originally started looking at NSTask (as that seems to be the most popular approach) but recently i just came across the system command. It looks like a far easier setup that NSTask. I've seen some questions/answers that say NSTask is the better approach, but I don't see
What are the advantages/disadvantages between the two
In what cases would one more likely to be used than the other
Any help/links/thoughts/ideas? (and yes.. i did a google search)
NSTask:
Can run his task in the background. Allows you to send interrupts and kills to the underlying process, and allows you to suspend or resume the underlying process without setting up threads yourself. Can also run synchronously if that's what you want.
Let's you work back and forth with Cocoa classes, like NSStrings without having to do a buncha conversions.
Let's you set I/O streams for the underlying process that differ from the caller's.
Better supported across all Apple platforms (like iOS) than system(3) -- I don't think system even works on iOS.
Requires Cocoa and Objective-C.
Doesn't interpret shell arguments or do path expansions of arguments.
system(3):
Better supported across all Unix-like platforms.
Can run a task with a one-liner.
Only requires C.
Runs in a shell and will interpret working directory and arguments like /bin/sh would.
For a Cocoa app I always use NSTask; I only use system if I'm doing something that must be C-only or I know will have to run under non-Mac environments. As it is, system is pretty brittle and the more robust solution is doing a fork-exec, because it allows you more control over streams and concurrent operation.
There are some differences. For some of them it is probably har to say in general, whether it is an advantage or not.
system() starts a shell. NSTask don't.
system() blocks. NSTask run asynchronously.
system() only takes args. NSTask works with pipes.
system() has only an integer exit code. NSTask works with pipes. (Yes, mentioned again. This is for output.)
system() takes a complete command line. To NSTask args can be passed in an array.
system() runs on the current directory. To NSTask you can pass a working directory.
This are some differences out of my mind without rechecking the documentation. It is an overview.

How to run a shell command in cocoa and get output?

After repeated searching I have not found an elegant solution to this issue: how to run a shell command in obj-c and get it's output. I have read many questions regarding this, but they all fail to answer my question.
Some get the exit value ( Get result from shell script objective-c ) others only run the command ( Cocoa/ Objective-C Shell Command Line Execution ), and finally others have me write the output to a file ( Execute a terminal command from a Cocoa app ).
I really would like to avoid writing/reading a file as it not a very clean solution.
Is there no way to read the output directly in obj-c? If so how?
The code from "doshellscript" from the first link (Get result from shell script objective-c) actually does return an NSString with the output of the command. If it's not working for you, maybe the command is outputting over stderr rather than stdin? Have you tried this yet? The standard mechanism for running commands in Cocoa is NSTask, so definitely at least start there.
Look at the class PRHTask. It is a replacement of NSTask, with completion blocks. https://bitbucket.org/boredzo/prhtask
Extract from the header:
First, rather than having to set your own pipe for standard output and error, you can tell the task to accumulate the output for you, and retrieve it when the task completes.
Second, when the process exits, rather than posting an NSNotification, a PRHTask will call either of two blocks that you provide. You can set them both to the same block if you want.
If your task needs admin privileges, you might want to look at STPrivilegedTask.

Call Perl Library from Objective-C cocoa

I have a Perl library i use to read some information from a file (closed format).
This library reads a file and returns an array of objects with the result.
Now i have to integrate that library (cannot implement it in cocoa right now) in a cocoa app. Basically call it and try to show the results in a list.
Is there some kind of bridge to call Perl libraries from ObjectiveC and get the results?
I've read something about using NSTask to call a perl script directly, and parse the result, but i wonder if it could be possible to do that call directly.
best regards.
You are perfectly right: NSTask is on Cocoa (not Cocoa-Touch) the right class for you. You can launch any subprocess, considering that this subprocess will inherit the environment from you main task (but of course you can apply different settings, e.g. the run directory).
The advantage with respect to "system()" is that NSTask "launch" method is non blocking so you can use it for long aysnchronous jobs (and be notified when it is over).
For the specific case of perl, just run the perl script as in command line: "/usr/bin/perl ..."
Finally you can make a try with PerlObjCBridge (link: PerlObjCBridge.pm man page) for a sort of interprocess communication between Objective-C objects and perl.
If you want a bridge, take a look at PerlObjCBridge. If you just want to call the script, I believe you can just use system(). Something like this:
system( [scriptCallNSString UTF8String] );

Objective c terminal application

Is there such thing? I need to make an application in Xcode to basically do what the terminal app does. With just an nstextfield as the input, a label for the terminal output, and a send button. All this needs to be done without terminal accually being open.
Is this possible? If so, can someone post a website or sample code?
It's certainly possible. The Terminal basically just runs a shell (bash by default). You could just launch an app that forwards entered text onto bash, and let bash do the work. Or you could interpret the input yourself. Bash is pretty simple, for the most part: you type in a program and arguments, it finds the program in the $PATH, and launches it with the given arguments. (Of course, bash gets a bit fancier, which pipes, input/output redirection, scripting, background tasks, etc., but if you don't need that in your application, you could ignore those features.) You can use NSTask, system(3), or the exec family of tasks to launch processes (probably NSTask is your best bet).

Easiest way to run shell script objective-c

I am a objective-c newbe and am wondering how to run a shell script in objective-c easiest way possible. I don't care about any of the output. I have tried system(), exec() and execl() and an NSTask. Those methods don't work for some reason... This is the shell script I am trying to run:
"mount_webdav http://idisk.mac.com/idisk_username/ /Volumes/idisk_username"
(Basically mounting my iDisk). Also, no password-boxes or any indication of it working shows.
It will work in applescript, and I have created the mount-point directory. None of the methods above do anything at all, or crash the application for some weird reason.
NSTask supplies everything you need. This should work:
NSArray *args=[NSArray arrayWithObjects:#"http://idisk.mac.com/idisk_username/",#"/Volumes/idisk_username",nil];
NSTask *mountTask=[[NSTask alloc] init];
[mountTask setLaunchPath:#"/sbin/mount_webdav"];
[mountTask launch];
Test all the complete command path and args from the command line first. I haven't used mount_webdav but I think it requires more args than you supplied.
Don't use shell scripts when you can help it. They're a good way to introduce serious bugs when you parameterize the script (e.g., mount_webdav %# %#).
Instead, use either NSTask, fork/exec directly, or (in Python) the subprocess module. You'll pass the three arguments as an array, rather than as a single string.
NSTask would be the way to do this in Cocoa. You might want to go over your code again, read up on the documentation for it (also look at the sample code there), and post specific questions about its usage here if you run into problems.