Несколько терминальных команд, использующих NSTask одновременно
Мне нужно запустить следующую команду из приложения 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), что не работает.
Когда я попробовал их отдельно в терминале, это тоже не сработало.
Какие-либо предложения? Спасибо
ОБНОВИТЬ:
После того, как вы следовали великому совету Кена Томаса, вот как это выглядит в быстрой версии:
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 ответ
Вы уверены, что вам нужно запустить эту команду и использовать 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
по команде. Вы создаете NSPipe
для каждой трубы (|
) в команде оболочки, которую вы эмулируете. Вы устанавливаете одну трубу как выход первой задачи и вход второй. Вы устанавливаете другой канал как выход второго и вход первого. Затем вы запускаете все три задачи и ждете, пока завершится последняя.
При желании вы можете использовать другой канал для стандартной ошибки каждой задачи и / или вывода последней задачи. Обязательно выполняйте асинхронное чтение из таких каналов одновременно с ожиданием завершения последней задачи (или, что еще лучше, не блокируйте ожидание последней задачи, а вернитесь к циклу обработки событий и дайте уведомлению задачи о ее завершении).
Аргументы для каждой задачи должны быть массивом. Если вы собираетесь попытаться выполнить эти задачи вместо использования надлежащего API, в идеале вы всегда должны иметь команду в виде массива, а не строки. Синтаксический анализ строки - это трудная задача, в зависимости от того, какие функции оболочки вы хотите эмулировать. Итак, для первой задачи путь запуска будет @"dscl"
и аргументы будут @[ @".", @"-read", @"/Users/user", @"JPEGPhoto" ]
, Аналогично для других задач.
Просто для полноты я скажу, что вы можете запустить полную командную строку, например, исходную строку, задействовав оболочку для ее анализа и запуска подпроцессов для каждой из подкоманд. Установите путь запуска @"/bin/sh"
и аргументы @[ @"-c", @"dscl . -read /Users/user JPEGPhoto | tail -1 | xxd -r -p > /Users/user/Desktop/user.jpg" ]
, Я действительно не рекомендую это, хотя. Предполагая, что настоящая команда, которую вы хотите выполнить, является динамической, и вы будете создавать командную строку программно, легко создавать проблемы. Если вы создадите строку, содержащую символы, которые обрабатывает оболочка специально, вы получите неожиданные результаты и, возможно, даже сделаете что-то опасное. Кроме того, лично мне кажется неправильным строить строку только для того, чтобы оболочка могла разорвать ее на части, когда вы могли бы выполнить оригинальную работу самостоятельно.