我正在尝试使用管道来处理需要多个输入的命令,但不太确定如何操作。这是我正在尝试做的事情的片段。我知道如何处理第一个输入,但我迷失了第二个输入-newstdinpass
NSTask *task = [[NSTask alloc] init];
NSPipe *pipe = [NSPipe pipe];
[task setLaunchPath: @"/bin/sh"];
[task setArguments: [NSArray arrayWithObjects: @"-c", @"/usr/bin/hdiutil chpass -oldstdinpass -newstdinpass /path/to/dmg", nil]];
[task setStandardInput:pipe];
[task launch];
[[pipe fileHandleForWriting] writeData:[@"thepassword" dataUsingEncoding:NSUTF8StringEncoding]];
[[pipe fileHandleForWriting] closeFile];
[task waitUntilExit];
[task release];
所以我知道以这种方式使用hdiutil
有点像黑客,但就管道方面而言,我是否采用了正确的方式?
感谢。
UPDATE :如果其他人对此感到疑惑,我的问题的一个快速解决方案是传入一个以null为终结的字符串,正如Ken Thomases在下面指出的那样。将[[NSString stringWithFormat:@"oldpass\0newpass\0"] dataUsingEncoding:NSUTF8StringEncoding]
用于管道。现在,仍然需要学习如何使用管道桥接多个NSTasks
...
答案 0 :(得分:3)
您可以创建多个NSTask
和一堆NSPipe
并将它们连接在一起,或者您可以使用sh -c
技巧为shell提供命令,并让它解析它并建立了所有的IPC。
示例:
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: @"/bin/sh"];
NSArray *arguments;
arguments = [NSArray arrayWithObjects: @"-c",
@"cat /usr/share/dict/words | grep -i ham | rev | tail -5", nil];
[task setArguments: arguments];
// and then do all the other jazz for running an NSTask.
参考: http://borkware.com/quickies/one?topic=nstask
现在,至于“正确的”命令执行功能,这是我通常使用的一个......
代码:
/*******************************************************
*
* MAIN ROUTINE
*
*******************************************************/
- (void)runCommand:(NSString *)cmd withArgs:(NSArray *)argsArray
{
//-------------------------------
// Set up Task
//-------------------------------
if (task) { [self terminate]; }
task = [[NSTask alloc] init];
[task setLaunchPath:cmd];
[task setArguments:argsArray];
[task setStandardOutput:[NSPipe pipe]];
[task setStandardError:[task standardOutput]];
//-------------------------------
// Set up Observers
//-------------------------------
[PP_NOTIFIER removeObserver:self];
[PP_NOTIFIER addObserver:self
selector:@selector(commandSentData:)
name: NSFileHandleReadCompletionNotification
object: [[task standardOutput] fileHandleForReading]];
[PP_NOTIFIER addObserver:self
selector:@selector(taskTerminated:)
name:NSTaskDidTerminateNotification
object:nil];
//-------------------------------
// Launch
//-------------------------------
[[[task standardOutput] fileHandleForReading] readInBackgroundAndNotify];
[task launch];
}
/*******************************************************
*
* OBSERVERS
*
*******************************************************/
- (void)commandSentData:(NSNotification*)n
{
NSData* d;
d = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem];
if ([d length])
{
NSString* s = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding];
NSLog(@"Received : %@",s);
}
[[n object] readInBackgroundAndNotify];
}
- (void)taskTerminated:(NSNotification*)n
{
[task release];
task = nil;
}
答案 1 :(得分:2)
您对管道的使用对我来说是正确的。
我不确定你为什么要使用/bin/sh
。只需设置NSTask
,其发布路径为@"/usr/bin/hdiutil"
,其参数为@"chpass"
,@"-oldstdinpass"
,@"-newstdinpass"
和{{1}的数组}。这更安全。例如,如果dmg的路径包含shell将解释的字符,如@"/path/to/dmg"
?
除非您明确希望利用shell功能,否则请不要使用shell。