3

我正在尝试使用管道来处理需要多个输入的命令,但不太确定该怎么做。这是我正在尝试做的一个片段。我知道如何处理第一个输入,但我对第二个输入中的管道感到迷茫-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以这种方式使用有点麻烦,但就管道而言,我是否以正确的方式进行操作?

谢谢。

更新:如果其他人对此感到疑惑,我的问题的一个快速解决方案是传递一个以 null 结尾的字符串,正如 Ken Thomases 在下面指出的那样。[[NSString stringWithFormat:@"oldpass\0newpass\0"] dataUsingEncoding:NSUTF8StringEncoding]入管使用。现在,仍然需要学习如何NSTasks用管道桥接多个......

4

2 回答 2

3

您可以创建多个NSTasks 和一堆NSPipes 并将它们连接在一起,或者您可以使用该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;
}
于 2012-04-19T02:45:10.893 回答
2

你对管道的使用对我来说是正确的。

我不确定你为什么使用/bin/sh. 只需设置NSTask,其启动路径为@"/usr/bin/hdiutil",其参数为@"chpass"@"-oldstdinpass"@"-newstdinpass"@"/path/to/dmg". 这要安全得多。例如,如果 dmg 的路径包含一个 shell 会解释的字符,比如$?

除非您特别利用 shell 功能,否则不要使用 shell。

于 2012-04-19T03:35:56.100 回答