You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用NSTask执行cd命令无输出,如何验证命令执行成功?

问题

我正尝试使用NSTask通过standardInput和standardOutput执行终端命令,ls、pwd等命令均可正常运行,但执行cd命令时standardOutput无任何输出。我清楚cd命令本身无显示响应,因此标准输出不会写入数据,但我需要判断该命令是否执行成功,以此更新UI。以下是我的代码,我使用NSFileHandleDataAvailableNotification读取输出,这对ping这类命令很有帮助:

-(void)setupTask {
    @autoreleasepool {
        // Commands are read from standard input:
        NSFileHandle *input = [NSFileHandle fileHandleWithStandardInput];
        
        NSPipe *inPipe = [NSPipe new]; // pipe for shell input
        NSPipe *outPipe = [NSPipe new]; // pipe for shell output
        NSPipe *errorPipe = [NSPipe new];
        
        task = [NSTask new];
        [task setLaunchPath:@"/bin/sh"];
        [task setStandardInput:inPipe];
        [task setStandardOutput:outPipe];
        [task setStandardError:errorPipe];
        
        [task launch];
        
        // Wait for standard input ...
        [input waitForDataInBackgroundAndNotify];
        // ... and wait for shell output.
        [[outPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
        [[errorPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
        
        
        // Wait asynchronously for standard input.
        // The block is executed as soon as some data is available on standard input.
        [[NSNotificationCenter defaultCenter] addObserverForName:NSFileHandleDataAvailableNotification
                                                          object:input queue: [NSOperationQueue mainQueue]
                                                      usingBlock:^(NSNotification *note)
         {
            NSData *inData = [input availableData];
            if ([inData length] == 0) {
                // EOF on standard input.
                [[inPipe fileHandleForWriting] closeFile];
            } else {
                // Read from standard input and write to shell input pipe.
                [[inPipe fileHandleForWriting] writeData:inData];
                
                // Continue waiting for standard input.
                [input waitForDataInBackgroundAndNotify];
            }
        }];
        
        // Wait asynchronously for shell output.
        // The block is executed as soon as some data is available on the shell output pipe.
        [[NSNotificationCenter defaultCenter] addObserverForName:NSFileHandleDataAvailableNotification
                                                          object:[outPipe fileHandleForReading] queue:[NSOperationQueue mainQueue]
                                                      usingBlock:^(NSNotification *note)
         {
            // Read from shell output
            NSData *outData = [[outPipe fileHandleForReading] availableData];
            if ([outData length] > 0) {
                NSString *outStr = [[NSString alloc] initWithData:outData encoding:NSUTF8StringEncoding];
                NSLog(@"Output: %@", outStr);
            }
            // Continue waiting for shell output.
            [[outPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
        }];
        
        [[NSNotificationCenter defaultCenter] addObserverForName:NSFileHandleDataAvailableNotification
                                                          object:[errorPipe fileHandleForReading] queue:[NSOperationQueue mainQueue]
                                                      usingBlock:^(NSNotification *note)
         {
            // Read from shell output
            NSData *outData = [[errorPipe fileHandleForReading] availableData];
            if ([outData length] > 0) {
                NSString *outStr = [[NSString alloc] initWithData:outData encoding:NSUTF8StringEncoding];
                    NSLog(@"Error: %@", outStr);
            }
            // Continue waiting for shell output.
            [[errorPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
        }];
    }
}

-(void)executeCommand:(NSString*)command {
    
    NSData* data = [command dataUsingEncoding:NSUTF8StringEncoding];
    NSError* error;
    [[[task standardInput] fileHandleForWriting] writeData:data error:&error];
    if (error != NULL) {
        NSLog(@"%@", [error localizedDescription]);
    }
    
    NSData* newLine = [@"\n" dataUsingEncoding:NSUTF8StringEncoding];
    [[[task standardInput] fileHandleForWriting] writeData:newLine error:&error];
    if (error != NULL) {
        NSLog(@"%@", [error localizedDescription]);
    }
}

-(void)runCommand {
    [self setupTask];
    [self executeCommand:@"cd Users"];
}
解决方案

方法1:通过echo $?获取命令退出码

cd命令执行成功时退出码为0,失败则为非0值。可以在执行cd后紧接着执行echo $?,读取该输出即可判断cd是否成功:

[self executeCommand:@"cd Users && echo $?"];

在输出回调中,解析得到的数字,0表示成功,其他值表示失败。

方法2:监听错误输出(stderr)

cd命令执行失败时(比如目录不存在),会将错误信息输出到stderr。你的代码已经监听了errorPipe,当cd失败时,error回调会收到类似cd: Users: No such file or directory的信息,通过判断是否有错误输出即可得知命令执行失败。

方法3:执行cd后主动获取当前工作目录

在执行cd命令后,执行pwd命令,读取输出的目录路径,对比是否是目标目录,以此验证cd是否成功:

[self executeCommand:@"cd Users && pwd"];

如果输出的路径包含目标目录名,则说明cd成功。

内容的提问来源于stack exchange,提问作者prabhu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 13:43:15