SwiftでCommand Line Toolを叩く時はProcess
を使いますが,grep
したい時どうすればいいのかわかりづらかったので備忘録
func extractDefaultInternet() {
// $ netstat -rnf inet | grep default
let pipe1 = Pipe()
let pipe2 = Pipe()
let netstat = Process()
netstat.launchPath = "/usr/bin/env"
netstat.arguments = ["netstat", "-rnf", "inet"]
netstat.standardOutput = pipe1
let grep = Process()
grep.launchPath = "/usr/bin/grep"
grep.arguments = ["default"]
grep.standardInput = pipe1
grep.standardOutput = pipe2
netstat.terminationHandler = { (_) in
grep.launch()
}
netstat.launch()
let data = pipe2.fileHandleForReading.readDataToEndOfFile()
guard let output = String(data: data, encoding: .utf8) else { return }
Swift.print(output)
}
こんな感じでPipe
を2個用意して,grep
の方のstandardInput
に一つ目のコマンドの出力結果のPipe
を入れて,一つ目の実行結果の後にgrep
を実行するようにterminationHandler
を登録してあげればOKです.
さらにgrep
したい時も同様の手順でOKです.
func en0() {
// $ netstat -rnf inet | grep default | grep en0
let pipe1 = Pipe()
let pipe2 = Pipe()
let pipe3 = Pipe()
let netstat = Process()
netstat.launchPath = "/usr/bin/env"
netstat.arguments = ["netstat", "-rnf", "inet"]
netstat.standardOutput = pipe1
let grep = Process()
grep.launchPath = "/usr/bin/grep"
grep.arguments = ["default"]
grep.standardInput = pipe1
grep.standardOutput = pipe2
let grep2 = Process()
grep2.launchPath = "/usr/bin/grep"
grep2.arguments = ["en0"]
grep2.standardInput = pipe2
grep2.standardOutput = pipe3
grep.terminationHandler = { (_) in
grep2.launch()
}
netstat.terminationHandler = { (_) in
grep.launch()
}
netstat.launch()
let data = pipe3.fileHandleForReading.readDataToEndOfFile()
guard let output = String(data: data, encoding: .utf8) else { return }
Swift.print(output)
}
追記
いろいろやっていたらもっと強い方法を見つけてしまいました.
func runShell(_ args: String) {
let process = Process()
process.launchPath = "/bin/sh"
process.arguments = ["-c", args]
let pipe = Pipe()
process.standardOutput = pipe
process.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
guard let output = String(data: data, encoding: .utf8) else { return }
Swift.print(output)
}
runShell("ifconfig | grep broadcast")
シェルを文字列を引数にして叩けばなんでもありやないか...