您可以使用精彩的NSTask
在Cocoa应用程序中运行脚本,并且效果很好。唯一的问题是我需要运行多个脚本,在我的应用程序中,脚本不能组合成一个文件或一个调用 - 它们必须由应用程序作为单独的任务运行。
问题是显然你只能在一个应用程序中运行一个NSTask
。我不明白为什么会这样,但遗憾的是,似乎是这样。我已经尝试了一切来调试它,但无论脚本是什么,多么简单或多么复杂,我的应用程序只会执行我运行的第一个NSTask
。 This problem has come up before虽然不那么直接,但似乎没有解决方案。
必须有一种方法可以在应用程序中运行多个脚本。有没有人知道我可以解决这个问题,或者可能是另一种运行脚本的方法?我需要做的就是运行一个非常短的bash脚本来执行“make install”。
以下是我如何运行NSTask的示例,以防它有用。
NSTask *task;
task = [NSTask launchedTaskWithLaunchPath: @"/bin/bash"
arguments:[NSArray arrayWithObjects: scriptPath, nil]
];
它确实适用于我的所有脚本,它只能运行一个而不是另一个。
答案 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]
正常,无论您使用垃圾收集,自动引用计数还是手动操作,都可以这样做引用计数。您不使用垃圾收集和自动引用计数的方法retain
,release
和autorelease
。
对评论的回应
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。