Reputation: 8158
I'm trying to chain shell command together in a Swift script. The actual commands in question are the output of gource
piped to the input of ffmpeg
, but here's a simplified, contrived example of what I'm trying to do:
let echo = Process()
echo.launchPath = "/usr/bin/env"
echo.arguments = ["echo", "foo\nbar\nbaz\nbaz", "|", "uniq"]
let pipe = Pipe()
echo.standardOutput = pipe
echo.launch()
echo.waitUntilExit()
// Get the data
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
print(output ?? "no output")
Expected output:
foo
bar
baz
Actual output:
foo
bar
baz
baz | uniq
The |
is being interpreted as part of the last argument. How can I chain commands together, so that data flows from one to the next, in a Swift script? I tried various combinations of assigning standardIn
and standardOut
and using Pipe()
between two Process
es, but either I'm doing it wrong, or I'm not connecting the right pieces together.
Upvotes: 5
Views: 2896
Reputation: 161
You should take a look a this. It's an example of an easy way to pipe by chaining. https://gist.github.com/eahrold/b5c5fd455225a8726e1cc31708e139db
so you can something like
let ls = Process("/bin/ls", ["-al"])
let grep = Process("/usr/bin/grep", ["com"])
let cut = Process("/usr/bin/awk", ["{print $3}"])
ls.pipe(grep).pipe(cut).complete {
message, status in
print("Your results: \(message)")
}
ls.launch()
Upvotes: -1
Reputation: 2764
For others that may be running into the same problem, here's what I derived from Zev's answer to fit with creating a SHA1 HMAC hash:
func getHMAC(forValue value: String, key: String) -> String {
let pipe = Pipe()
let echo = Process()
echo.launchPath = "/usr/bin/env"
echo.arguments = ["echo", "-n", value]
echo.standardOutput = pipe
let task = Process()
task.launchPath = "/usr/bin/env"
task.arguments = ["openssl", "sha1", "-hmac", key]
task.standardInput = pipe
let output = Pipe()
task.standardOutput = output
echo.launch()
task.launch()
task.waitUntilExit()
let data = output.fileHandleForReading.readDataToEndOfFile()
return NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String
}
This is especially useful when making simple API calls from Swift scripts which require a hash in the HTTP header. As far as I found, this was the only way it was possible (since we cannot make use of the Objective-C CommonCrypto framework in Swift scripts)
Upvotes: 0
Reputation: 8158
I got an answer with help from zadr:
import Foundation
let pipe = Pipe()
let echo = Process()
echo.launchPath = "/usr/bin/env"
echo.arguments = ["echo", "foo\nbar\nbaz\nbaz"]
echo.standardOutput = pipe
let uniq = Process()
uniq.launchPath = "/usr/bin/env"
uniq.arguments = ["uniq"]
uniq.standardInput = pipe
let out = Pipe()
uniq.standardOutput = out
echo.launch()
uniq.launch()
uniq.waitUntilExit()
let data = out.fileHandleForReading.readDataToEndOfFile()
let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
print(output ?? "no output")
Upvotes: 12