Macos NSTask';实时输出
我有一个PHP脚本,其中包含mutlipleMacos NSTask';实时输出,macos,nstask,Macos,Nstask,我有一个PHP脚本,其中包含mutliplesleep()命令。我想用NSTask在我的应用程序中执行它。我的脚本如下所示: echo "first\n"; sleep(1); echo "second\n"; sleep(1); echo "third\n"; 我可以使用通知异步执行任务: - (void)awakeFromNib { NSTask *task = [[NSTask alloc] init]; [task setLaunchPath: @"/usr/bin/p
sleep()
命令。我想用NSTask
在我的应用程序中执行它。我的脚本如下所示:
echo "first\n"; sleep(1); echo "second\n"; sleep(1); echo "third\n";
我可以使用通知异步执行任务:
- (void)awakeFromNib {
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath: @"/usr/bin/php"];
NSArray *arguments;
arguments = [NSArray arrayWithObjects: @"-r", @"echo \"first\n\"; sleep(1); echo \"second\n\"; sleep(1); echo \"third\n\";", nil];
[task setArguments: arguments];
NSPipe *p = [NSPipe pipe];
[task setStandardOutput:p];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskExited:) name:NSTaskDidTerminateNotification object:task];
[task launch];
}
- (void)taskExited:(NSNotification *)notif {
NSTask *task = [notif object];
NSData *data = [[[task standardOutput] fileHandleForReading] readDataToEndOfFile];
NSString *str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(@"%@",str);
}
我的输出是(当然是2秒后):
我的问题是:如何在打印完这三个单词后立即获取它们?您可以使用NSFileHandle的
WaitForDataInBackground和Notify方法在脚本将数据写入其输出时接收通知。但是,只有当解释器立即发送字符串时,这才有效。如果它缓冲输出,则在任务退出后将收到一个通知
- (void)awakeFromNib {
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath: @"/usr/bin/php"];
NSArray *arguments;
arguments = [NSArray arrayWithObjects: @"-r", @"echo \"first\n\"; sleep(1); echo \"second\n\"; sleep(1); echo \"third\n\";", nil];
[task setArguments: arguments];
NSPipe *p = [NSPipe pipe];
[task setStandardOutput:p];
NSFileHandle *fh = [p fileHandleForReading];
[fh waitForDataInBackgroundAndNotify];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedData:) name:NSFileHandleDataAvailableNotification object:fh];
[task launch];
}
- (void)receivedData:(NSNotification *)notif {
NSFileHandle *fh = [notif object];
NSData *data = [fh availableData];
if (data.length > 0) { // if data is found, re-register for more data (and print)
[fh waitForDataInBackgroundAndNotify];
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@" ,str);
}
}
以下是ughoavgfhw在swift中的回答,以供参考
override func awakeFromNib() {
// Setup the task
let task = NSTask()
task.launchPath = "/usr/bin/php"
task.arguments = ["-r", "echo \"first\n\"; sleep(1); echo \"second\n\"; sleep(1); echo \"third\n\";"]
// Pipe the standard out to an NSPipe, and set it to notify us when it gets data
let pipe = NSPipe()
task.standardOutput = pipe
let fh = pipe.fileHandleForReading
fh.waitForDataInBackgroundAndNotify()
// Set up the observer function
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.addObserver(self, selector: "receivedData:", name: NSFileHandleDataAvailableNotification, object: nil)
// You can also set a function to fire after the task terminates
task.terminationHandler = {task -> Void in
// Handle the task ending here
}
task.launch()
}
func receivedData(notif : NSNotification) {
// Unpack the FileHandle from the notification
let fh:NSFileHandle = notif.object as NSFileHandle
// Get the data from the FileHandle
let data = fh.availableData
// Only deal with the data if it actually exists
if data.length > 1 {
// Since we just got the notification from fh, we must tell it to notify us again when it gets more data
fh.waitForDataInBackgroundAndNotify()
// Convert the data into a string
let string = NSString(data: data, encoding: NSASCIIStringEncoding)
println(string!)
}
}
如果任务在管道中产生大量输出,则此构造是必需的。仅调用pipe.fileHandleForReading.readDataToEndOfFile()
将不起作用,因为任务正在等待清空管道,以便在程序等待数据结束时可以写入更多内容。因此,您的程序将挂起。此通知和观察者构造允许异步读取管道,从而防止上述僵局。我尝试过,但它只记录“first”。“第二个”和“第三个”记录在任务终止时…通过在-receiveData
中放置额外的readinbackground和notify
来解决它。谢谢你的主意!经过一段时间的努力,我更新了代码。您需要另一个waitForDataInBackgroundAndNotify
,而不是readInBackgroundAndNotify
。使用创建长结果的find
命令尝试此代码段,该代码段需要额外的[fh waitForDataInBackgroundAndNotify]
,以获取完整数据。希望这对像我这样的初学者有所帮助。我曾尝试在iOS的Swift(见下文)中使用这段代码,但有趣的是,只有当我的应用程序连接到调试器时,我才能实时收到回电。。。如果我单独运行它,那么在最后我只收到一个调用,而不是一个实时的流。。知道为什么吗?
override func awakeFromNib() {
// Setup the task
let task = NSTask()
task.launchPath = "/usr/bin/php"
task.arguments = ["-r", "echo \"first\n\"; sleep(1); echo \"second\n\"; sleep(1); echo \"third\n\";"]
// Pipe the standard out to an NSPipe, and set it to notify us when it gets data
let pipe = NSPipe()
task.standardOutput = pipe
let fh = pipe.fileHandleForReading
fh.waitForDataInBackgroundAndNotify()
// Set up the observer function
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.addObserver(self, selector: "receivedData:", name: NSFileHandleDataAvailableNotification, object: nil)
// You can also set a function to fire after the task terminates
task.terminationHandler = {task -> Void in
// Handle the task ending here
}
task.launch()
}
func receivedData(notif : NSNotification) {
// Unpack the FileHandle from the notification
let fh:NSFileHandle = notif.object as NSFileHandle
// Get the data from the FileHandle
let data = fh.availableData
// Only deal with the data if it actually exists
if data.length > 1 {
// Since we just got the notification from fh, we must tell it to notify us again when it gets more data
fh.waitForDataInBackgroundAndNotify()
// Convert the data into a string
let string = NSString(data: data, encoding: NSASCIIStringEncoding)
println(string!)
}
}