如何使用Swift输出到STDERR?

JEs*_*ala 32 macos swift

我正在尝试使用Xcode 6和新的Swift语言为OS X创建命令行工具.如何将输出发送到stderr?这是用println完成的吗?

小智 25

对于Swift 4.x:

import Darwin
fputs("hello from libc\n", stderr)
Run Code Online (Sandbox Code Playgroud)


Rob*_*ier 18

可能是更好的方法,但您可以使用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))
Run Code Online (Sandbox Code Playgroud)

  • 是的,似乎应该有更简单的方法来做到这一点。Python 和 C 都有更简单的方法来做到这一点。我很惊讶 Swift 也不会。如果没有更好的结果,我会将其标记为正确答案。 (2认同)
  • 这并不让我感到震惊.除此之外,没有Cocoa方法可以做到这一点.只有一种C方式(stdout),这不是Cocoa.Apple确实将Swift专注于"app"问题,而不是命令行问题.(我在命令行上做了很多工作......) (2认同)
  • @GeneDeLisa 打印出 `(foo, 2)`。 (2认同)

Rya*_*ner 16

这是一个Swift 3片段

来自https://gist.github.com/algal/0a9aa5a4115d86d5cc1de7ea6d06bd91

import Foundation

var standardError = FileHandle.standardError

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

print("I am printed to stderr",to:&standardError)
Run Code Online (Sandbox Code Playgroud)


Man*_*nav 12

不是一个单独的答案,但建立在Rob Napier的答案之上,我们可以创建一个类似stderr的对象,这样当Apple提供stderr时,没有太大的改变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)
Run Code Online (Sandbox Code Playgroud)

编辑:截至2015年8月26日,Xcode 7 Beta 6,您需要toStream:参数名称,如下所示:

println("on-stderr", toStream:&mx_stderr)
Run Code Online (Sandbox Code Playgroud)

  • 或者只是`func write(string:String){fputs(string,stderr)}`:) (2认同)
  • 我很惊讶地发现 Swift 的 `print` 在下面使用了 C 的 `stdio` - 我写了一个函数,它使用 `funopen` 来重定向“正常”的 `stdout`,它也拦截了 `print()`。 (2认同)

pos*_*sen 9

Swift 4,类似于Ryan的解决方案,但不是扩展FileHandle,而是创建了一个新结构,它还允许您创建一个StdErr特定类并避免全局.

struct StandardErrorOutputStream: TextOutputStream {
    let stderr = FileHandle.standardError

    func write(_ string: String) {
        guard let data = string.data(using: .utf8) else {
            return // encoding failure
        }
        stderr.write(data)
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

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


Rud*_*vič 8

Xcode 13.2+ 和 Swift 5.5+

模型:

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

用法:

var standardError = StandardError()
print("Error!", to: &standardError)
Run Code Online (Sandbox Code Playgroud)


Pin*_*one 7

以下是三种增加复杂性的不同方法:

Erica Sadun在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
Run Code Online (Sandbox Code Playgroud)

对于使用NSFileHandle.fileHandleWithStandardError的略有不同的方法,请参阅:http://crunchybagel.com/building-command-line-tools-with-swift/ 标题为:写入stdout/stderr,但此方法不使用Swift的打印库功能.

对于一个非常疯狂的旅程,请查看rosettacode.org提供的方法,使用NSOutputStream,网址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")
}
Run Code Online (Sandbox Code Playgroud)