gpt4 book ai didi

objective-c - 无法从NSTask的stdout获得中间输出?

转载 作者:太空宇宙 更新时间:2023-11-04 11:48:33 24 4
gpt4 key购买 nike

我已经为一个简单的python脚本编写了一个异步exec方法。
当python脚本打印到stdout时,一切都很好。
当有一个NSTask在那里(期望来自用户的输入),它确实得到输入罚款,但它不打印之前的数据raw_input
发生什么事?

- (NSString*)exec:(NSArray *)args environment:(NSDictionary*)env action:(void (^)(NSString*))action completed:(void (^)(NSString*))completed
{
_task = [NSTask new];
_output = [NSPipe new];
_error = [NSPipe new];
_input = [NSPipe new];
NSFileHandle* outputF = [_output fileHandleForReading];
NSFileHandle* errorF = [_error fileHandleForReading];
NSFileHandle* inputF = [_input fileHandleForWriting];

__block NSString* fullOutput = @"";

NSMutableDictionary* envs = [NSMutableDictionary dictionary];

NSArray* newArgs = @[@"bash",@"-c"];

[_task setLaunchPath:@"/usr/bin/env"];
if (env)
for (NSString* key in env)
envs[key] = env[key];

if ([envs count]) [_task setEnvironment:envs];

NSString* cmd = @"";

cmd = [cmd stringByAppendingString:[[[self sanitizedArgs:args] componentsJoinedByString:@" "] stringByAppendingString:@" && echo \":::::$PWD:::::\""]];

[_task setArguments:[newArgs arrayByAddingObject:cmd]];
[_task setStandardOutput:_output];
[_task setStandardError:_error];
[_task setStandardInput:_input];

void (^outputter)(NSFileHandle*) = ^(NSFileHandle *file){
NSData *data = [file availableData];
NSString* str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

NSLog(@"Output: %@",str);

action(str);
fullOutput = [fullOutput stringByAppendingString:str];
};

void (^inputter)(NSFileHandle*) = ^(NSFileHandle *file) {
NSLog(@"In inputter");
NSData *data = [[_task.standardOutput fileHandleForReading] availableData];
NSString* str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

NSLog(@"Output: %@",str);
};

[outputF setReadabilityHandler:outputter];
[errorF setReadabilityHandler:outputter];
//[inputF setWriteabilityHandler:inputter];

[_task setTerminationHandler:^(NSTask* task){
NSLog(@"Terminated: %@",fullOutput);
completed(fullOutput);

//[task.standardOutput fileHandleForReading].readabilityHandler = nil;
//[task.standardError fileHandleForReading].readabilityHandler = nil;
//[task.standardInput fileHandleForWriting].writeabilityHandler = nil;
//[task terminate];
//task = nil;
}];

[_task launch];

//[[_input fileHandleForWriting] waitForDataInBackgroundAndNotify];

return @"";
}

我到处寻找解决办法,但似乎什么也没找到。看起来好像有大量的演练和教程,但是-有趣的巧合-它们通常避免处理任何 raw_input的含义

最佳答案

这与父进程(带有NSTask对象的进程)无关。这都是关于孩子过程的行为。子进程实际上还没有将字节写入管道。
stdio man page开始:
最初,标准错误流是无缓冲的;标准输入和输出
当且仅当流不引用
交互式或“终端”设备,由isatty(3)功能确定。
实际上,所有新打开的流都指向终端设备
默认为行缓冲,并将挂起的输出写入此类流
每当读取这样的输入流时自动执行。注意这个
仅适用于“真读取”;如果读取请求可以通过
现有缓冲数据不会发生自动刷新。在这些情况下,
或者在打印了
在输出端子上,有必要按(3)标准
输出前先停止计算,这样输出才会出现。
或者,可以通过setvbuf(3)函数修改这些默认值。
在您的情况下,标准输入和输出实际上并不涉及交互/终端设备。因此,标准输出是完全缓冲的(即块缓冲,而不是行缓冲或无缓冲)。仅当stdio库内部的缓冲区已满、流已关闭或流上调用fflush()时,才会刷新它。
您期望的行为(读取输入时自动刷新标准输出)仅在流连接到交互/终端设备时发生。
父进程无法影响子进程的缓冲行为,除非使用伪终端设备而不是输入和输出管道。然而,这是一项复杂且容易出错的工作。除此之外,必须对子进程进行编码,以设置标准输出的缓冲模式或定期刷新它。

关于objective-c - 无法从NSTask的stdout获得中间输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56858559/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com