Skip to content

Instantly share code, notes, and snippets.

@jcmosc
Created April 30, 2025 18:39
Show Gist options
  • Save jcmosc/83a37f524ba77e60db1338494962c496 to your computer and use it in GitHub Desktop.
Save jcmosc/83a37f524ba77e60db1338494962c496 to your computer and use it in GitHub Desktop.
Temporarily print standard output to a custom text output stream in Swift
import Foundation
/// Additionally writes any data written to standard output into the given output stream.
///
/// - Parameters:
/// - output: An output stream to receive the standard output text
/// - encoding: The encoding to use when converting standard output into text.
/// - body: A closure that is executed immediately.
/// - Returns: The return value, if any, of the `body` closure.
func printingStandardOutput<T>(to output: inout TextOutputStream, encoding: String.Encoding = .utf8, body: () -> T) async -> T {
var result: T? = nil
let consumer = Pipe() // reads from stdout
let producer = Pipe() // writes to stdout
let stream = AsyncStream<Data> { continuation in
let clonedStandardOutput = dup(STDOUT_FILENO)
defer {
dup2(clonedStandardOutput, STDOUT_FILENO)
close(clonedStandardOutput)
}
dup2(STDOUT_FILENO, producer.fileHandleForWriting.fileDescriptor)
dup2(consumer.fileHandleForWriting.fileDescriptor, STDOUT_FILENO)
consumer.fileHandleForReading.readabilityHandler = { fileHandle in
let chunk = fileHandle.availableData
if chunk.isEmpty {
continuation.finish()
} else {
continuation.yield(chunk)
producer.fileHandleForWriting.write(chunk)
}
}
result = body()
try! consumer.fileHandleForWriting.close()
}
for await chunk in stream {
output.write(String(data: chunk, encoding: encoding)!)
}
return result!
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment