0

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

单链表。-读取/用户/用户 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 的好建议之后,这就是它在 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)
}
4

1 回答 1

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 特殊处理的字符的字符串,您将得到意想不到的结果,甚至可能做一些危险的事情。此外,就个人而言,当您可以直接自己完成原始工作时,仅构建一个字符串以便外壳可以将其拆开,这感觉是错误的。

于 2014-09-13T08:28:16.727 回答