有没有办法运行两个或更多NSTasks?

时间:2012-03-07 17:05:23

标签: objective-c macos cocoa nstask

您可以使用精彩的NSTask在Cocoa应用程序中运行脚本,并且效果很好。唯一的问题是我需要运行多个脚本,在我的应用程序中,脚本不能组合成一个文件或一个调用 - 它们必须由应用程序作为单独的任务运行。

问题是显然你只能在一个应用程序中运行一个NSTask。我不明白为什么会这样,但遗憾的是,似乎是这样。我已经尝试了一切来调试它,但无论脚本是什么,多么简单或多么复杂,我的应用程序只会执行我运行的第一个NSTaskThis problem has come up before虽然不那么直接,但似乎没有解决方案。

必须有一种方法可以在应用程序中运行多个脚本。有没有人知道我可以解决这个问题,或者可能是另一种运行脚本的方法?我需要做的就是运行一个非常短的bash脚本来执行“make install”。

以下是我如何运行NSTask的示例,以防它有用。

NSTask *task;
task = [NSTask launchedTaskWithLaunchPath: @"/bin/bash"
                                arguments:[NSArray arrayWithObjects: scriptPath, nil]
        ];

它确实适用于我的所有脚本,它只能运行一个而不是另一个。

4 个答案:

答案 0 :(得分:5)

当然,您可以使用多个NSTask。只需使用其init方法而不是方便方法,并手动设置属性:

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

答案 1 :(得分:1)

这里有一些混淆“只运行一次”。

NSTask创建一个 new 进程,它是一个只能运行一次的创建进程;您可以使用NSTask创建任意数量的不同进程,每个进程可以运行一次。您创建的每个差异流程都可以执行不同的或相同的二进制文件 - 因此,如果您想创建许多流程,每个流程都可以执行/bin/bash

因此,为每个脚本创建一个 new NSTask并运行它。

注意:类方法launchedTaskWithLaunchPath:arguments创建NSTask并启动进程运行。您还可以使用NSTask(或[NSTask new])创建[[NSTask alloc] init],设置其参数,然后启动它。

注意:根据您对其他答案的评论,使用[NSTask new][[NSTask alloc] init] 正常,无论您使用垃圾收集,自动引用计数还是手动操作,都可以这样做引用计数。您不使用垃圾收集和自动引用计数的方法retainreleaseautorelease

对评论的回应

user1168440已经展示了一种更通用的调用NSTask的方法,但正如在此处使用类方法的确认是正在执行的两个shell脚本。首先在/tmp中创建两个脚本:

tmp $ cat script1.sh
#!/bin/bash
echo `date -u` script one >>/tmp/script.txt
tmp $ cat script2.sh
#!/bin/bash
echo `date -u` script two >>/tmp/script.txt

一个简单的Obj-C应用程序:

#import "TasksAppDelegate.h"

@implementation TasksAppDelegate

@synthesize window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
   [NSTask launchedTaskWithLaunchPath:@"/bin/bash" arguments:[NSArray arrayWithObject:@"/tmp/script1.sh"]]; 
   [NSTask launchedTaskWithLaunchPath:@"/bin/bash" arguments:[NSArray arrayWithObject: @"/tmp/script2.sh"]]; 
}

@end

在Xcode中运行并检查结果:

tmp $ cat script.txt
Sat Mar 10 05:12:43 UTC 2012 script two
Sat Mar 10 05:12:43 UTC 2012 script one

这两个任务都已运行,因此这不会阻止您的代码正常工作。可能是您的一个shell脚本需要从标准输入读取,失败,因此似乎根本不运行?

通常,设置管道的方法是捕获输出(并且可以提供输入)是使用NSTask的更好方法,但是launchedTaskWithLaunchPath:arguments在捕获输出(或提供输入)时工作正常不是必需的。

答案 2 :(得分:0)

这是一个简单的方法,用于使用NSTask运行多个命令:

First setup a method to accept your commands
-(NSString *) runForOutput:(NSString *)command {

//initialize the command line to run
NSString *runCmd = [[NSString alloc] initWithString:@"/bin/bash"];
NSArray *runArgs = [[NSArray alloc] initWithObjects:@"-c",command,nil];

//update proper label
return [self runThisCmd:runCmd withArgs:runArgs];
}

next setup a method to call NSTask
-(NSString *) runThisCmd:(NSString *) runString withArgs:(NSArray *)runArgs  {

NSTask *task = [NSTask new];
[task setLaunchPath:runString];
[task setArguments:runArgs];
[task setStandardOutput:[NSPipe pipe]];
[task setStandardInput: [NSPipe pipe]];
[task setStandardError: [task standardOutput]];
[task launch];

NSData *stdOuput = [[[task standardOutput] fileHandleForReading] readDataToEndOfFile];
[task waitUntilExit];  
NSString *outputString = [[NSString alloc] initWithData:stdOuput encoding:NSUTF8StringEncoding];
return outputString;
}

Now run a bunch of commands
- (void) runSomething {

    NSString *hostnameLong = [self runForOutput:@"hostname"];
    NSString *hostnameShort = [self runForOutput:@"hostname -s"];
    NSString *startDate = [self runForOutput:@"date '+Start Date: %Y-%m-%d'"];
    NSString *startTime = [self runForOutput:@"date '+Start Time: %H:%M:%S'"];

}

The output of the commands are in the strings. You can work with it from there.
This method is best for short, quick command lines due to the [task waitUntilExit]
call that will block. This works great to simulate what I call "unix one-liners". 
I use it sometimes from awakeFromNib to grab one to two bits of info I may need. 
For long running scripts you would convert to an async approach and use notifications to update variables.

答案 3 :(得分:-1)

尝试使用线程的概念。通过在不同的线程上分配每个NStask,您可以运行两个或更多NStasks。