一次使用NSTask的多个终端命令

时间:2014-09-13 07:08:20

标签: macos cocoa nstask nspipe

我需要从OSX应用程序运行以下命令:

dscl。 -read / Users / user JPEGPhoto |尾巴-1 | xxd -r -p> /Users/user/Desktop/user.jpg

我尝试了几件事,例如:

func runScript(launchPath:String, scriptName:String) {

    let task = NSTask()
    task.launchPath = launchPath
    task.arguments = NSArray(objects: scriptName)

    let pipe = NSPipe()
    task.standardOutput = pipe
    task.launch()

    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    let output: String = NSString(data: data, encoding: NSUTF8StringEncoding)

}

func runCommand(command: String) -> (output: String, exitStatus: Int) {
    let tokens = command.componentsSeparatedByString(" ")
    let launchPath = tokens[0]
    let arguments = tokens[1..<tokens.count]

    let task = NSTask()
    task.launchPath = launchPath
    task.arguments = Array(arguments)
    let stdout = NSPipe()
    task.standardOutput = stdout

    task.launch()
    task.waitUntilExit()

    let outData = stdout.fileHandleForReading.readDataToEndOfFile()
    let outStr = NSString(data: outData, encoding: NSUTF8StringEncoding)
    return (outStr, Int(task.terminationStatus))
}

问题是这些方法每次调用都会执行一个命令,因此我必须调用它们三次(dscl / tail / xxd)并且不起作用。

当我在终端中单独尝试它们时,它也没有工作。

有什么建议吗?感谢

更新:

跟随Ken Thomases&#39;很好的建议,这就是它在swift中的样子:

import Collaboration
func saveUserPicture() {
    var userImage:NSImage = CBUserIdentity(posixUID: getuid(), authority: CBIdentityAuthority.defaultIdentityAuthority()).image() as NSImage
    var userImageData:NSData = NSBitmapImageRep.representationOfImageRepsInArray(userImage.representations, usingType: NSBitmapImageFileType.NSJPEGFileType, properties: nil )
    userImageData.writeToFile("/Users/user/Desktop/file.jpg", atomically: true)
}

1 个答案:

答案 0 :(得分:0)

您确定需要运行该命令并使用NSTask吗?该信息应通过直接API提供。

特别是,我认为以下内容可以为您提供用户的图像:

NSImage* image = [[CBUserIdentity identityWithName:@"user" authority:[CBIdentityAuthority defaultIdentityAuthority]] image];

如果你真的想要,你可以将它保存为文件:

NSData* data = [NSBitmapImageRep representationOfImageRepsInArray:image.representations usingType:NSJPEGFileType properties:nil];
[data writeToURL:someURL atomically:YES];

根据您实际提出的问题,您需要为每个命令使用一个NSTask。您在要模拟的shell命令中为每个管道(NSPipe)创建|。您将一个管道设置为第一个任务的输出和第二个任务的输入。您将另一个管道设置为第二个管道的输出和第一个管道的输入。然后运行所有三个任务并等待最后一个完成。

如果需要,可以使用另一个管道来处理每个任务的标准错误和/或上一个任务的输出。确保在等待最后一个任务退出的同时异步读取这些管道(或者更好的是,不要阻止等待最后一个任务,但是回到事件循环并让任务在完成时通知你)。

每个任务的参数应该是一个数组。如果您打算尝试运行这些任务而不是使用正确的API,那么理想情况下,您最好将命令作为数组而不是字符串。根据要模拟的shell的哪些功能,解析字符串是一件很难的事情。因此,对于第一个任务,启动路径为@"dscl",参数为@[ @".", @"-read", @"/Users/user", @"JPEGPhoto" ]。同样适用于其他任务。

为了完整起见,我说你可以运行一个完整的命令行,就像你的原始字符串一样,通过登记shell解析它并为每个子命令运行子进程。将启动路径设置为@"/bin/sh",将参数设置为@[ @"-c", @"dscl . -read /Users/user JPEGPhoto | tail -1 | xxd -r -p > /Users/user/Desktop/user.jpg" ]。不过,我真的不推荐这个。假设您要运行的实际命令是动态的,并且您将以编程方式构建命令行,则很容易产生问题。如果你构建一个包含shell专门处理的字符的字符串,你会得到意想不到的结果,甚至可能做一些危险的事情。另外,就个人而言,构建一个字符串只是觉得错误,以便当你可以直接自己完成原创作品时shell可以分开。