一个交互式Unix命令的Cocoa包装器

9

好的,我知道您可以使用Objective-C创建NSTask来运行命令行工具:

NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: @"/usr/bin/gdb"];
[task launch];

我想知道是否有一种方法可以与交互式命令行工具(如 gdb)进行通信。这将涉及根据用户交互提供命令输入(例如使用 gdbrunkillquit 命令),然后根据其输出的信息做出反应。

2个回答

3
你可以使用 NSTask 的 setStandardInput:setStandardOutput: 以及 setStandardError: 选择器与 NSPipe 实例结合起来与被启动的程序进行通讯。
例如,要读取任务的输出:
task = [[NSTask alloc] init];
[task setStandardOutput: [NSPipe pipe]];
[task setStandardError: [task standardOutput]]; // Get standard error output too
[task setLaunchPath: @"/usr/bin/gdb"];
[task launch];

您可以通过以下方法获取一个NSFileHandle实例,以便用来读取任务的输出:

NSFileHandle *readFromMe = [[task standardOutput] fileHandleForReading]; 

为了建立一个向gdb发送命令的管道,你需要添加以下代码:
[task setStandardInput: [NSPipe pipe]];

在启动任务之前,请先获取NSFileHandle
NSFileHandle *writeToMe = [[task standardInput] fileHandleForWriting];

你好!你会使用类似 NSData *data = [inString dataUsingEncoding:NSUTF8StringEncoding]; [writeToMe writeData:data]; 这样的代码发送命令吗?我尝试过了,但好像不起作用。 - brendanzab
3
@bjz 这应该可以运行。不要忘记在字符串的末尾添加 \n,以模拟用户在输入命令后按下回车键。 - sjs

3
使用 NSTask类setStandardInput:setStandardOutput: 方法。
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");
}

你好,你已经让这个工作了吗?我似乎在实现这个过程中遇到了一些问题。我没有收到任何通知。我正在使用它来执行 git clone。我需要通知让我知道何时要求我输入用户名和密码。有什么帮助吗? - Just a coder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接