How can I output to STDERR with Swift?

MacosSwift

Macos Problem Overview


I'm trying to make a command line tool for OS X with Xcode 6 and the new Swift language. How can I send output to stderr? Is this done with println?

Macos Solutions


Solution 1 - Macos

For Swift 4.x:

import Darwin
fputs("hello from libc\n", stderr)

Solution 2 - Macos

Here is a Swift 3 snippet modified from https://gist.github.com/algal/0a9aa5a4115d86d5cc1de7ea6d06bd91.

import Foundation

var standardError = FileHandle.standardError

extension FileHandle: TextOutputStream {
  public func write(_ string: String) {
    let data = Data(string.utf8)
    self.write(data)
  }
}

print("I am printed to stderr", to: &standardError)

Solution 3 - Macos

May be a better way to do it, but you can use NSFileHandle:

import Foundation

// Create a file handle to work with
let stderr = NSFileHandle.fileHandleWithStandardError()

// Build up a string; whatever you want
let stuff = "something"
let something = "I'm a string with \(stuff) in it\n"

// Write it
stderr.writeData(something.dataUsingEncoding(NSUTF8StringEncoding))

Solution 4 - Macos

Not really a separate answer, but building on top of Rob Napier's answer, we can create a stderr like object so that there is not much to change when Apple comes around to providing stderr as an OutputStreamType:

import Foundation

class StandardErrorOutputStream: OutputStreamType {
  func write(string: String) {
    let stderr = NSFileHandle.fileHandleWithStandardError()
    stderr.writeData(string.dataUsingEncoding(NSUTF8StringEncoding))
  }
}

var mx_stderr = StandardErrorOutputStream()

println("on-stdout")
println("on-stderr", &mx_stderr)

EDIT: As of 8/26/2015, Xcode 7 Beta 6, you need the toStream: parameter name, like so:

println("on-stderr", toStream:&mx_stderr)

Solution 5 - Macos

Swift 4, similar to Ryan's solution but instead of extending the FileHandle, created a new struct which also lets you create a StdErr specific class and avoids the global.

struct StandardErrorOutputStream: TextOutputStream {
    let stderr = FileHandle.standardError

    func write(_ string: String) {
        guard let data = string.data(using: .utf8) else {
            fatalError() // encoding failure: handle as you wish
        }
        stderr.write(data)
    }
}

Usage example:

do { 
    try somethingThatMightFail() 
} catch let error {
    var errStream = StandardErrorOutputStream()
    print("\(error)", to: &errStream)
    exit(EXIT_FAILURE)
}

Solution 6 - Macos

Here are three different methods of increasing complexity:

Compliments of Erica Sadun at http://ericasadun.com/2015/06/09/swift-2-0-how-to-print/:

public struct StderrOutputStream: OutputStreamType {
    public mutating func write(string: String) {
        fputs(string, stderr)
    }
}

public var errStream = StderrOutputStream()

debugPrint("Hello", toStream: &errStream) // prints with new line

For a slightly different method using NSFileHandle.fileHandleWithStandardError, see: http://crunchybagel.com/building-command-line-tools-with-swift/ in the section titled: Writing to stdout / stderr, but this method does not use Swift's print library function.

And for a really crazy ride, check out the method offered by rosettacode.org using NSOutputStream at https://www.rosettacode.org/wiki/Hello_world/Standard_error#Swift:

let out = NSOutputStream(toFileAtPath: "/dev/stderr", append: true)
let err = "Goodbye, World!".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
out?.open()
let success = out?.write(UnsafePointer<UInt8>(err!.bytes), maxLength: err!.length)
out?.close()

if let bytes = success {
    print("\nWrote \(bytes) bytes")
}

Solution 7 - Macos

Xcode 13.2+ and Swift 5.5+

Model:

class StandardError: TextOutputStream {
  func write(_ string: String) {
    try! FileHandle.standardError.write(contentsOf: Data(string.utf8))
  }
}

Usage:

var standardError = StandardError()
print("Error!", to: &standardError)

Solution 8 - Macos

A condensed and modernized version of @RobNapiers suggested solution:

"A line of text"
    .data(using: .utf8)
    .map(FileHandle.standardError.write)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJEscalaView Question on Stackoverflow
Solution 1 - Macosi40westView Answer on Stackoverflow
Solution 2 - MacosRyan HeitnerView Answer on Stackoverflow
Solution 3 - MacosRob NapierView Answer on Stackoverflow
Solution 4 - MacosManavView Answer on Stackoverflow
Solution 5 - MacospossenView Answer on Stackoverflow
Solution 6 - MacosPineconeView Answer on Stackoverflow
Solution 7 - MacosRudolf AdamkovičView Answer on Stackoverflow
Solution 8 - MacosEraView Answer on Stackoverflow