3

複数の入力を必要とするコマンドをパイプを使用して処理しようとしていますが、その方法がよくわかりません。これが私がやろうとしていることの抜粋です。最初の入力の処理方法は知っていますが、2番目の入力の配管に迷っています-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、この方法で使用するのは少しハックですが、パイプに関しては、正しい方法で実行していますか?

ありがとう。

更新:他の人がこれについて疑問に思っている場合、私の問題の簡単な解決策は、Ken Thomasesが以下で指摘したように、nullで終了する文字列を渡すことです。[[NSString stringWithFormat:@"oldpass\0newpass\0"] dataUsingEncoding:NSUTF8StringEncoding]パイプに使用します。今でもNSTasks、パイプで複数をブリッジする方法を学ぶ必要があります...

4

2 に答える 2

3

複数NSTaskのと一連の を作成NSPipeしてそれらをフックするか、sh -cトリックを使用してシェルにコマンドを供給し、それを解析してすべての 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/shNSTask起動パスが@"/usr/bin/hdiutil"で、引数が 、 、 、 の配列である を@"chpass"設定@"-oldstdinpass"する@"-newstdinpass"だけです@"/path/to/dmg"。これははるかに安全です。たとえば、dmg へのパスに、シェルが解釈する文字が含まれている場合はどうなります$か?

特にシェル機能を利用したい場合を除き、シェルは使用しないでください。

于 2012-04-19T03:35:56.100 に答える