2015-04-08 4 views
8

я запускать некоторые команды в терминале с этим кодом:Получить вывод на терминал после команды быстрого

system("the command here") 

А после я хочу знать, что является результатом выполнения этой команды, например, если я запускаю

system("git status") 

Я хочу прочитать фактическую информацию об изменениях в моем репо. Есть ли способ сделать это быстро?

+0

Возможный дубликат [команда Xcode 6 скор система()] (HTTP: // StackOverflow.ком/вопросы/26399301/Xcode-6-скор-системы команд). –

+0

@MartinR, нет информации о том, как запускать сразу несколько команд или запускать команды за один сеанс. –

+0

Для выполнения команды и ее вывода вы должны использовать NSTask. Для нескольких команд создайте и выполните несколько NSTasks. –

ответ

20

NSTask классно запустить другую программу в качестве подпроцесс. Вы можете записать выход программы, выход ошибки, статус выхода и многое другое.

Расширение на мой ответ на xcode 6 swift system() command, здесь простая функция полезности для запуска команды синхронно, и возвращает выходной, выходной ошибка и код выхода (в настоящее время обновляется для Swift 2):

func runCommand(cmd : String, args : String...) -> (output: [String], error: [String], exitCode: Int32) { 

    var output : [String] = [] 
    var error : [String] = [] 

    let task = NSTask() 
    task.launchPath = cmd 
    task.arguments = args 

    let outpipe = NSPipe() 
    task.standardOutput = outpipe 
    let errpipe = NSPipe() 
    task.standardError = errpipe 

    task.launch() 

    let outdata = outpipe.fileHandleForReading.readDataToEndOfFile() 
    if var string = String.fromCString(UnsafePointer(outdata.bytes)) { 
     string = string.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet()) 
     output = string.componentsSeparatedByString("\n") 
    } 

    let errdata = errpipe.fileHandleForReading.readDataToEndOfFile() 
    if var string = String.fromCString(UnsafePointer(errdata.bytes)) { 
     string = string.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet()) 
     error = string.componentsSeparatedByString("\n") 
    } 

    task.waitUntilExit() 
    let status = task.terminationStatus 

    return (output, error, status) 
} 

Пример использования:

let (output, error, status) = runCommand("/usr/bin/git", args: "status") 
print("program exited with status \(status)") 
if output.count > 0 { 
    print("program output:") 
    print(output) 
} 
if error.count > 0 { 
    print("error output:") 
    print(error) 
} 

или, если вы заинтересованы только в выходные, но не в сообщения об ошибках или код выхода:

let output = runCommand("/usr/bin/git", args: "status").output 

Выходные данные и вывод ошибок возвращаются в виде массива строк, одна строка для каждой строки.

Первый аргумент runCommand() должен быть полным путем к исполняемому файлу , например "/usr/bin/git". Вы можете запустить программу, используя оболочку (которая является то, что system() также делает):

let (output, error, status) = runCommand("/bin/sh", args: "-c", "git status") 

Преимущество заключается в том, что «мерзавец» исполняемый файл автоматически найден по пути поиска по умолчанию. Недостатком является то, что вы должны правильно указывать/исключать аргументы , если они содержат пробелы или другие символы , которые имеют особое значение в оболочке.


Обновление для Swift 3:

func runCommand(cmd : String, args : String...) -> (output: [String], error: [String], exitCode: Int32) { 

    var output : [String] = [] 
    var error : [String] = [] 

    let task = Process() 
    task.launchPath = cmd 
    task.arguments = args 

    let outpipe = Pipe() 
    task.standardOutput = outpipe 
    let errpipe = Pipe() 
    task.standardError = errpipe 

    task.launch() 

    let outdata = outpipe.fileHandleForReading.readDataToEndOfFile() 
    if var string = String(data: outdata, encoding: .utf8) { 
     string = string.trimmingCharacters(in: .newlines) 
     output = string.components(separatedBy: "\n") 
    } 

    let errdata = errpipe.fileHandleForReading.readDataToEndOfFile() 
    if var string = String(data: errdata, encoding: .utf8) { 
     string = string.trimmingCharacters(in: .newlines) 
     error = string.components(separatedBy: "\n") 
    } 

    task.waitUntilExit() 
    let status = task.terminationStatus 

    return (output, error, status) 
} 
+1

Я все еще не могу запускать несколько программ за один сеанс. Например, если вывод для 'status' не содержит слов« ничего »и« ясно »(некоторые изменения были внесены), мне нужно запустить' git add .', а затем 'git commit' и' git push origin master' –

+0

@NikitinRoman: Что значит «одна сессия»? Невозможно запустить 'runCommand ("/usr/bin/git "," status ")' first, а затем 'runCommand ("/usr/bin/git "," add ",". ")' И, наконец, 'runCommand («/ usr/bin/git», «push», «origin», «master») '? –

+0

Во-первых, мне нужно запустить 'cd Project' и после него один за другим все эти команды, без изменения каталога –

2

system порождает новый процесс, поэтому вы не можете захватить его выход. Эквивалент, который дает вам способ сделать это было бы popen, которые вы могли бы использовать так:

import Darwin 

let fp = popen("ping -c 4 localhost", "r") 
var buf = Array<CChar>(count: 128, repeatedValue: 0) 

while fgets(&buf, CInt(buf.count), fp) != nil, 
     let str = String.fromCString(buf) { 
    print(str) 
} 

fclose(fp) 

Однако, не делать это таким образом. Используйте NSTask как Martin describes.

редактировать: на основании Вашего запроса, чтобы запустить несколько команд параллельно, вот некоторые, вероятно, неразумно код:

import Darwin 

let commands = [ 
    "tail /etc/hosts", 
    "ping -c 2 localhost", 
] 

let fps = commands.map { popen($0, "r") } 

var buf = Array<CChar>(count: 128, repeatedValue: 0) 

let results: [String] = fps.map { fp in 
    var result = "" 
    while fgets(&buf, CInt(buf.count), fp) != nil, 
      let str = String.fromCString(buf) { 
     result += str 
    } 
    return result 
} 

fps.map { fclose($0) } 

println("\n\n----\n\n".join(map(zip(commands,results)) { "\($0):\n\($1)" })) 

(серьезно, используйте NSTask)

+0

Второй аргумент' fgets() 'должен быть фактическим размером буфера :) - Одна из причин, почему я избегаю' popen() 'if возможно, что вы должны правильно указывать/избегать аргументов, если они содержат пробелы или любые специальные символы, которые могут быть уродливыми. –

+0

D'oh! Вы, конечно, правы, я в основном публикую это, потому что я поражен тем, что C-общение настолько плавное. –

+1

есть ли способ запуска нескольких команд один за другим и получения вывода для каждого из них? –