我使用下面的函数运行shell命令,但是在命令运行时似乎无法获取它来打印输出。例如,如果我运行/ usr / sbin / system_profiler,则必须等到命令执行完毕,才能看到输出。
当命令仍在运行时,如何打印shell命令的输出?
func runCommand(cmd: String, args: String...) -> (output: [String], error: [String], exitCode: Int32) {
print("running shell command")
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
print("shell end")
return (output, error, status)
}
答案 0 :(得分:0)
您必须使您的任务与readInBackgroundAndNotify
异步。
类似这样(未经测试)的东西,它使用terminationHandler
并添加readCompletionNotification
观察者来获取通知。
var output = ""
func runCommand(cmd: String, args: String..., completion: @escaping (String, String, Int32) -> Void) {
print("running shell command")
let task = Process()
task.launchPath = cmd
task.arguments = args
let outpipe = Pipe()
task.standardOutput = outpipe
let errpipe = Pipe()
task.standardError = errpipe
task.terminationHandler = { [unowned self] returnedTask in
NotificationCenter.default.removeObserver(self,
name: FileHandle.readCompletionNotification,
object: (returnedTask.standardOutput as! Pipe).fileHandleForReading)
let status = returnedTask.terminationStatus
if status == 0 {
completion(output, "", status)
} else {
let errorData = errpipe.fileHandleForReading.readDataToEndOfFile()
let errorString = String(data:errorData, encoding: .utf8)!
completion("", errorString, status)
}
}
let outputHandle = (task.standardOutput as! Pipe).fileHandleForReading
NotificationCenter.default.addObserver(forName: FileHandle.readCompletionNotification, object: outputHandle, queue: OperationQueue.current, using: { notification in
if let data = notification.userInfo?[NSFileHandleNotificationDataItem] as? Data, !data.isEmpty {
output.append(String(data: data, encoding: . utf8)!)
} else {
task.terminate()
return
}
outputHandle.readInBackgroundAndNotify()
})
outputHandle.readInBackgroundAndNotify()
task.launch()
}
如果要在接收数据时打印数据,请用output.append(String(data: data, encoding: . utf8)!)
替换print(String(data: data, encoding: . utf8)!)
,然后可能也不需要完成处理程序。
答案 1 :(得分:0)
具体来说,阻止原因为outpipe.fileHandleForReading.readDataToEndOfFile()
您可以尝试以下方法进行验证: ...
task.standardOutput = outpipe
let errpipe = Pipe()
task.standardError = errpipe
task.launch()
repeat{
let outdata = outpipe.fileHandleForReading.readData(ofLength: 100) //.readDataToEndOfFile()
if var string = String(data: outdata, encoding: .utf8) {
string = string.trimmingCharacters(in: .newlines)
output = string.components(separatedBy: "\n")
print(output)
}
let errdata = errpipe.fileHandleForReading.readData(ofLength: 100)// .readDataToEndOfFile()
if var string = String(data: errdata, encoding: .utf8) {
string = string.trimmingCharacters(in: .newlines)
error = string.components(separatedBy: "\n")
}} while (task.isRunning)
或添加readerHandler:
outpipe.fileHandleForReading.readabilityHandler = { file in
let outdata = fileHandle.readData(ofLength: 100)
if var string = String(data: outdata, encoding: .utf8) {
string = string.trimmingCharacters(in: .newlines)
print( string.components(separatedBy: "\n"))
}
然后,您可以有多种方法来避免这种情况,请在其他线程中的Timer或Observer中点击链接。